Compare commits

...

77 Commits
7.2.6 ... 4.0.3

Author SHA1 Message Date
6ccb93728e docs: add changelog for 4.0.3 2017-04-20 23:41:41 -05:00
b54a957ef4 release: cut the 4.0.3 release 2017-04-20 23:39:36 -05:00
21c14a79fa fix(compiler): suppress another closure warning (#16137)
closure compiler warns in generated .ngfactory.ts files:
```
WARNING - property createInternal already defined on superclass module$contents$..$core$src$linker$ng_module_factory_NgModuleInjector; use @override to override it
```

PR Close #16137
2017-04-20 23:39:36 -05:00
eed2d456d7 refactor(tsc-wrapped): cleanup (#16178)
PR Close #16178
2017-04-20 23:39:36 -05:00
719c232321 fix(core): distribute externs for testability API (#16179)
Workaround for #11119

PR Close #16179
2017-04-20 23:39:36 -05:00
bd033b69c1 feat: add support for TS 2.3 2017-04-20 23:39:36 -05:00
5b92f7ee6d fix(core): benchmarks - enable ng1 benchmark again
Also make it match the ng2 benchmark.
2017-04-20 23:39:36 -05:00
20ffb4196d fix(benchpress): chrome - prevent trace buffer overflow 2017-04-20 23:39:36 -05:00
11e6f45387 build: bump protractor to 4.0.14 2017-04-20 23:39:36 -05:00
a30a73c2aa fix(compiler): ignore calls to unresolved symbols in metadata
This only shows up in the language service. Calls to symbols
that are not resolve resulted in null instead of being resolved
causing the language service to see exceptions when the null
was not expected such as in the animations array.

Fixes #15969
2017-04-20 23:39:36 -05:00
fb94c9937c feat(upgrade): fixes for allow setting the angularjs lib at runtime
- always have a value for `angular`, even if no angular is on the page
- use `const` instead of `function` to allow to export a variable `module`
  without breaking tsickle / closure.
2017-04-20 23:39:36 -05:00
b3259e26fe feat(upgrade): allow setting the angularjs lib at runtime (#15168)
Readds 8ad464d90e.
2017-04-20 23:39:36 -05:00
be406f8464 fix(compiler): Inform user where Quoted error was thrown 2017-04-20 23:39:36 -05:00
5cab3b146e fix(router): prevent RouterLinkActive from causing an infinite CD loop
fixes #15825
2017-04-20 23:39:36 -05:00
eff6216319 fix(language-service): only use canonical symbols
Language service was treating some alias TypeScript symbols as if
they where the canonical symbol. If the symbol in scope is an alias
of another symbol the symbol should be converted to the canonical
symbol.
2017-04-20 23:39:35 -05:00
88b2ab09ea Revert "fix(compiler): ignore calls to unresolved symbols in metadata (#15970)"
This reverts commit ce47d33cd9.
2017-04-20 23:39:35 -05:00
5ad6d55a45 Revert "feat(upgrade): allow setting the angularjs lib at runtime (#15168)"
This reverts commit 8ad464d90e.

Breaks G3.
2017-04-20 23:39:35 -05:00
c81c7c0920 fix(compiler): fix build error in xliff2 2017-04-20 23:39:35 -05:00
6f8e23b061 refactor(router): drop the InternalRoute interface 2017-04-20 23:39:35 -05:00
dc9711107d refactor(router): misc refactoring 2017-04-20 23:39:35 -05:00
4c0c1e5fa0 feat(compiler): Implement i18n XLIFF 2.0 serializer (#14185)
- Ensure that the result passes OASIS XLIFF 2.0 schema validation
- Use <ph/> for self-closing placeholder tags
- Use <pc></pc> for other placeholder tags
- Check for the correct XLIFF file version
- Add ICU support

fixes #11735
2017-04-20 23:39:35 -05:00
06ef0908c7 feat(upgrade): allow setting the angularjs lib at runtime (#15168)
This PR adds an ability to reset the angularjs library, which is often needed when Angular
is loaded lazily using RequireJS.
2017-04-20 23:39:35 -05:00
a893d5e0a9 fix(packaging): increased buffer size (#15840) 2017-04-20 23:39:35 -05:00
44afa5a03a fix(core): key-value differ changes iteration (#15968)
fixes #14997
2017-04-20 23:39:35 -05:00
0733f8d3e1 fix(compiler): ignore calls to unresolved symbols in metadata (#15970)
This only shows up in the language service. Calls to symbols
that are not resolve resulted in null instead of being resolved
causing the language service to see exceptions when the null
was not expected such as in the animations array.

Fixes #15969
2017-04-20 23:39:35 -05:00
6604a4dc40 refactor(compiler): cleanup (#15960) 2017-04-20 23:39:35 -05:00
96c63a92e2 fix(platform-server): handle innerText (#15818) 2017-04-20 23:39:35 -05:00
c444b1575f fix(tsc-wrapped): collect new expressions with no arguments (#15908)
Fixes #15906
2017-04-20 23:39:35 -05:00
2b676192f6 docs: add changelog for 4.1.0-beta.1 2017-04-20 23:39:34 -05:00
14a2d1a6f7 docs: add changelog for 4.0.2 2017-04-11 14:56:13 -07:00
61e089931f release: cut the 4.0.2 release 2017-04-11 14:50:12 -07:00
cbf30cb101 ci: add jasonaden to the router 2017-04-11 14:38:46 -07:00
2f41b52e78 fix(router): fix query param parsing 2017-04-11 14:38:46 -07:00
dcf60da16d refactor(router): cleanup & simplifications 2017-04-11 14:38:45 -07:00
9c9f409364 test(router): enable running the campaign in non-ES6 browsers
Closes #15806.
2017-04-11 14:38:45 -07:00
b44b983c1f test(router): test preloading when a module is already loaded 2017-04-11 14:38:45 -07:00
978f80985c fix(router): the preloader use the module from the loaded config 2017-04-11 14:38:45 -07:00
c10e50cf38 fix(tsc-wrapped): ensure valid path separators in metadata
* Fixes that `tsc-wrapped` stores invalid path separators in the bundled metadata files. Previous errors could have been: `Cannot find module '.corecoordinationnique-selection-dispatcher'.` (See https://github.com/angular/material2/issues/3834)
* Fixes failing tests on Windows. Now all tooling tests are green on Windows.

Related to #15403
2017-04-11 14:38:45 -07:00
168a2eb5bf fix(language-service): detect when there isn't a tsconfig.json
Fixes #15874
2017-04-11 14:38:44 -07:00
c9c7acd484 fix(language-service): parse extended i18n forms 2017-04-11 14:34:15 -07:00
5b99533315 fix(language-service): initialize static reflector correctly
Fixes #15768
2017-04-11 14:34:14 -07:00
037805b741 style(router): fix typo in router preloader method 2017-04-11 14:34:14 -07:00
0861fda69c fix(language-service): avoid throwing exceptions when reporting metadata errors 2017-04-11 14:34:13 -07:00
feae7b6059 fix(language-service): resolve any parameter types to any result 2017-04-11 14:34:12 -07:00
e4277a0869 fix(language-service): improve resilience to incomplete information 2017-04-11 14:34:12 -07:00
1864ccb3dd fix(compiler): fix inheritance for AOT with summaries (#15583)
Allows to inherit ctor args, lifecycle hooks and statics from a class
in another compilation unit. 
Will error if trying to inherit from a class in another compilation unit 
that has an `@Component` / `@Directive` / `@Pipe` / `@NgModule`.
2017-04-11 14:34:11 -07:00
6b79ab5abe docs: add changelog for 4.0.1 2017-03-29 16:27:40 -07:00
53c12a84dc release: cut the 4.0.1 release 2017-03-29 16:26:06 -07:00
ca665303f4 fix(core): fix inheritance in JIT mode for TS 2.1 (#15599)
Fixes #15502
2017-03-29 16:19:15 -07:00
0fe4985756 fix(language-service): correctly determine base members of types (#15600)
Fixes #15460
2017-03-29 16:19:09 -07:00
74087cb39d docs(http): remove deprecated stuff and outdated plunkrs (#15598) 2017-03-29 15:18:03 -07:00
902bb2f026 fix(compiler): throw when a component defines both template and templateUrl (#15572)
Closes #15566
2017-03-29 10:29:00 -07:00
23bf34853c refactor(router): cleanup & simplification (#15436) 2017-03-29 10:15:00 -07:00
8c4b963927 fix(core): Update types for TypeScript nullability support (#15472) 2017-03-29 10:14:55 -07:00
bfa4f70204 fix(language-service): don't require reflect-metadata module to be provided (#15569)
Fixes #15568
2017-03-29 10:14:48 -07:00
d481f6d150 docs(core): fix API docs for Injector.get 2017-03-29 10:14:38 -07:00
fd6114561b perf(router): don't create new serializer every time UrlTree.toString is called (#15565) 2017-03-29 10:11:21 -07:00
c82851172e fix(animations): make sure style calculations are not computed too early (#15540)
Closes #15507
2017-03-29 10:11:06 -07:00
75478b2078 fix(router): should run CanActivate after CanDeactivate guards
Closes #14059
Closes #15467
2017-03-29 10:11:00 -07:00
cdbb3dbd2a refactor(router): fix tests structure 2017-03-29 10:10:53 -07:00
e72124c888 fix(core): fix the key/value differ (#15539)
fixes #15457
2017-03-29 10:10:43 -07:00
b8c0a97e35 fix(core): check for undefined on normalizeDebugBindingValue (#15503)
DebugServices is parsing false atributes values incorrectly.
Parse5 expects a string value for attributes, but currently boolean is being sent.

Closes #15494
2017-03-29 10:10:37 -07:00
5597fd3180 fix(language-service): improve performance of updateModuleAnalysis() (#15543) 2017-03-29 10:10:26 -07:00
a88413f871 fix(compiler): ignore errors when evaluating base classes (#15560)
Fixes #15536
2017-03-29 10:10:22 -07:00
aa116524e6 refactor(router): improve flatten fn
closes #15505
2017-03-29 10:10:10 -07:00
4a5ad7ba30 refactor(router): use object spread operator instead of merge fn 2017-03-29 10:10:06 -07:00
d74e4d0633 fix(core): improve error msg for invalid KeyValueDiffer.diff arg (#15489)
Closes #15402
2017-03-29 10:09:55 -07:00
a2c2b87aa3 fix(language-service): be resilient to invalidate ordering (#15470)
Fixes #15466
2017-03-29 10:09:19 -07:00
8f4ea3e4b8 docs(core): fix typo and example in InjectionToken doc (#15449)
The doc included an example that didn't use InjectionToken.
2017-03-29 10:08:22 -07:00
bf25e94f19 fix(language-service): guard access to Symbol.members (#15529)
Fixes #15528 

What is the current behavior?
The language service access TypeScript's Symbol.members without checking for null or undefined.
What is the new behavior?
The access is guarded.
2017-03-29 10:08:06 -07:00
7983414e6a ci: add tbosch and vicb as approvers of the language service (#15530) 2017-03-29 10:07:58 -07:00
8248eba3e2 docs: in doc comments, replace [aA]ngular2 with Angular (#15463) 2017-03-29 10:07:44 -07:00
a65487528f fix(compiler): allow single quotes into named interpolations (#15461)
Fixes #15318
2017-03-29 10:07:32 -07:00
426b3a19b7 refactor: use object spread operator rather than merge (#15426) 2017-03-29 10:07:14 -07:00
2360676a7b fix(router): shouldn't execute CanLoad when a route has been loaded
Closes #14475
Closes #15438
2017-03-29 10:07:01 -07:00
ce3e03ff1a refactor(router): polishing 2017-03-29 10:06:52 -07:00
858c11cf7b docs: clarify querying all descendants (#15400)
Fixes #14417
Updated example to illustrate @ContentChildren default behavior (only query direct children), and how to query for nested elements/all descendants.
2017-03-29 10:06:09 -07:00
196 changed files with 4990 additions and 2709 deletions

View File

@ -176,7 +176,8 @@ groups:
- "packages/language-service/*"
users:
- chuckjaz #primary
# needs secondary
- tbosch #secondary
- vicb
- IgorMinar #fallback
- mhevery #fallback
@ -185,8 +186,8 @@ groups:
files:
- "packages/router/*"
users:
- vicb #primary
# needs secondary
- jasonaden
- vicb
- IgorMinar #fallback
- mhevery #fallback

View File

@ -1,3 +1,110 @@
<a name="4.0.3"></a>
## [4.0.3](https://github.com/angular/angular/compare/4.0.2...4.0.3) (2017-04-21)
### Bug Fixes
* **benchpress:** chrome - prevent trace buffer overflow ([d216f94](https://github.com/angular/angular/commit/d216f94))
* **compiler:** fix build error in xliff2 ([1870347](https://github.com/angular/angular/commit/1870347))
* **compiler:** ignore calls to unresolved symbols in metadata ([d4038ab](https://github.com/angular/angular/commit/d4038ab)), closes [#15969](https://github.com/angular/angular/issues/15969)
* **compiler:** ignore calls to unresolved symbols in metadata ([#15970](https://github.com/angular/angular/issues/15970)) ([db25f08](https://github.com/angular/angular/commit/db25f08)), closes [#15969](https://github.com/angular/angular/issues/15969)
* **compiler:** Inform user where Quoted error was thrown ([3184cc5](https://github.com/angular/angular/commit/3184cc5))
* **compiler:** suppress another closure warning ([#16137](https://github.com/angular/angular/issues/16137)) ([72e240a](https://github.com/angular/angular/commit/72e240a))
* **core:** benchmarks - enable ng1 benchmark again ([ccac4c6](https://github.com/angular/angular/commit/ccac4c6))
* **core:** distribute externs for testability API ([#16179](https://github.com/angular/angular/issues/16179)) ([e377d9d](https://github.com/angular/angular/commit/e377d9d))
* **core:** key-value differ changes iteration ([#15968](https://github.com/angular/angular/issues/15968)) ([a8600dc](https://github.com/angular/angular/commit/a8600dc)), closes [#14997](https://github.com/angular/angular/issues/14997)
* **language-service:** only use canonical symbols ([786093a](https://github.com/angular/angular/commit/786093a))
* **packaging:** increased buffer size ([#15840](https://github.com/angular/angular/issues/15840)) ([88ad490](https://github.com/angular/angular/commit/88ad490))
* **platform-server:** handle innerText ([#15818](https://github.com/angular/angular/issues/15818)) ([7de340d](https://github.com/angular/angular/commit/7de340d))
* **router:** prevent `RouterLinkActive` from causing an infinite CD loop ([4479c42](https://github.com/angular/angular/commit/4479c42)), closes [#15825](https://github.com/angular/angular/issues/15825)
* **tsc-wrapped:** collect new expressions with no arguments ([#15908](https://github.com/angular/angular/issues/15908)) ([41cac9e](https://github.com/angular/angular/commit/41cac9e)), closes [#15906](https://github.com/angular/angular/issues/15906)
### Features
* **compiler:** Implement i18n XLIFF 2.0 serializer ([#14185](https://github.com/angular/angular/issues/14185)) ([a7d8edd](https://github.com/angular/angular/commit/a7d8edd)), closes [#11735](https://github.com/angular/angular/issues/11735)
* **upgrade:** allow setting the angularjs lib at runtime ([#15168](https://github.com/angular/angular/issues/15168)) ([a75d056](https://github.com/angular/angular/commit/a75d056))
* **upgrade:** allow setting the angularjs lib at runtime ([#15168](https://github.com/angular/angular/issues/15168)) ([4f172b0](https://github.com/angular/angular/commit/4f172b0))
* **upgrade:** fixes for allow setting the angularjs lib at runtime ([bb6932d](https://github.com/angular/angular/commit/bb6932d))
* add support for TS 2.3 ([5cf101f](https://github.com/angular/angular/commit/5cf101f))
<a name="4.1.0-beta.1"></a>
# [4.1.0-beta.1](https://github.com/angular/angular/compare/4.1.0-beta.0...4.1.0-beta.1) (2017-04-12)
### Bug Fixes
* **compiler:** fix inheritance for AOT with summaries ([#15583](https://github.com/angular/angular/issues/15583)) ([8ef621a](https://github.com/angular/angular/commit/8ef621a))
* **language-service:** avoid throwing exceptions when reporting metadata errors ([7764c5c](https://github.com/angular/angular/commit/7764c5c))
* **language-service:** detect when there isn't a tsconfig.json ([258d539](https://github.com/angular/angular/commit/258d539)), closes [#15874](https://github.com/angular/angular/issues/15874)
* **language-service:** improve resilience to incomplete information ([71a8627](https://github.com/angular/angular/commit/71a8627))
* **language-service:** initialize static reflector correctly ([fe0d02f](https://github.com/angular/angular/commit/fe0d02f)), closes [#15768](https://github.com/angular/angular/issues/15768)
* **language-service:** parse extended i18n forms ([bde9771](https://github.com/angular/angular/commit/bde9771))
* **language-service:** resolve any parameter types to any result ([5fbb0d0](https://github.com/angular/angular/commit/5fbb0d0))
* **router:** fix query param parsing ([a487563](https://github.com/angular/angular/commit/a487563))
* **router:** the preloader use the module from the loaded config ([6d12aa9](https://github.com/angular/angular/commit/6d12aa9))
* **tsc-wrapped:** ensure valid path separators in metadata ([96aa236](https://github.com/angular/angular/commit/96aa236))
### Features
* **animations:** Update types for TypeScript nullability support ([38d75d4](https://github.com/angular/angular/commit/38d75d4)), closes [#15870](https://github.com/angular/angular/issues/15870)
* **benchpress:** Update types for TypeScript nullability support ([14669f2](https://github.com/angular/angular/commit/14669f2))
* **common:** Update types for TypeScript nullability support ([d8b73e4](https://github.com/angular/angular/commit/d8b73e4))
* **compiler:** Update types for TypeScript nullability support ([09d9f5f](https://github.com/angular/angular/commit/09d9f5f))
* **language-service:** Update types for TypeScript nullability support ([540581d](https://github.com/angular/angular/commit/540581d))
<a name="4.0.2"></a>
## [4.0.2](https://github.com/angular/angular/compare/4.0.1...4.0.2) (2017-04-11)
### Bug Fixes
* **compiler:** fix inheritance for AOT with summaries ([#15583](https://github.com/angular/angular/issues/15583)) ([1864ccb](https://github.com/angular/angular/commit/1864ccb))
* **language-service:** avoid throwing exceptions when reporting metadata errors ([0861fda](https://github.com/angular/angular/commit/0861fda))
* **language-service:** detect when there isn't a tsconfig.json ([168a2eb](https://github.com/angular/angular/commit/168a2eb)), closes [#15874](https://github.com/angular/angular/issues/15874)
* **language-service:** improve resilience to incomplete information ([e4277a0](https://github.com/angular/angular/commit/e4277a0))
* **language-service:** initialize static reflector correctly ([5b99533](https://github.com/angular/angular/commit/5b99533)), closes [#15768](https://github.com/angular/angular/issues/15768)
* **language-service:** parse extended i18n forms ([c9c7acd](https://github.com/angular/angular/commit/c9c7acd))
* **language-service:** resolve any parameter types to any result ([feae7b6](https://github.com/angular/angular/commit/feae7b6))
* **router:** fix query param parsing ([2f41b52](https://github.com/angular/angular/commit/2f41b52))
* **router:** the preloader use the module from the loaded config ([978f809](https://github.com/angular/angular/commit/978f809))
* **tsc-wrapped:** ensure valid path separators in metadata ([c10e50c](https://github.com/angular/angular/commit/c10e50c))
<a name="4.0.1"></a>
## [4.0.1](https://github.com/angular/angular/compare/4.0.0...4.0.1) (2017-03-29)
### Bug Fixes
* **animations:** make sure style calculations are not computed too early ([#15540](https://github.com/angular/angular/issues/15540)) ([c828511](https://github.com/angular/angular/commit/c828511)), closes [#15507](https://github.com/angular/angular/issues/15507)
* **compiler:** allow single quotes into named interpolations ([#15461](https://github.com/angular/angular/issues/15461)) ([a654875](https://github.com/angular/angular/commit/a654875)), closes [#15318](https://github.com/angular/angular/issues/15318)
* **compiler:** ignore errors when evaluating base classes ([#15560](https://github.com/angular/angular/issues/15560)) ([a88413f](https://github.com/angular/angular/commit/a88413f)), closes [#15536](https://github.com/angular/angular/issues/15536)
* **compiler:** throw when a component defines both template and templateUrl ([#15572](https://github.com/angular/angular/issues/15572)) ([902bb2f](https://github.com/angular/angular/commit/902bb2f)), closes [#15566](https://github.com/angular/angular/issues/15566)
* **core:** check for undefined on normalizeDebugBindingValue ([#15503](https://github.com/angular/angular/issues/15503)) ([b8c0a97](https://github.com/angular/angular/commit/b8c0a97)), closes [#15494](https://github.com/angular/angular/issues/15494)
* **core:** fix inheritance in JIT mode for TS 2.1 ([#15599](https://github.com/angular/angular/issues/15599)) ([ca66530](https://github.com/angular/angular/commit/ca66530)), closes [#15502](https://github.com/angular/angular/issues/15502)
* **core:** fix the key/value differ ([#15539](https://github.com/angular/angular/issues/15539)) ([e72124c](https://github.com/angular/angular/commit/e72124c)), closes [#15457](https://github.com/angular/angular/issues/15457)
* **core:** improve error msg for invalid KeyValueDiffer.diff arg ([#15489](https://github.com/angular/angular/issues/15489)) ([d74e4d0](https://github.com/angular/angular/commit/d74e4d0)), closes [#15402](https://github.com/angular/angular/issues/15402)
* **core:** Update types for TypeScript nullability support ([#15472](https://github.com/angular/angular/issues/15472)) ([8c4b963](https://github.com/angular/angular/commit/8c4b963))
* **language-service:** be resilient to invalidate ordering ([#15470](https://github.com/angular/angular/issues/15470)) ([a2c2b87](https://github.com/angular/angular/commit/a2c2b87)), closes [#15466](https://github.com/angular/angular/issues/15466)
* **language-service:** correctly determine base members of types ([#15600](https://github.com/angular/angular/issues/15600)) ([0fe4985](https://github.com/angular/angular/commit/0fe4985)), closes [#15460](https://github.com/angular/angular/issues/15460)
* **language-service:** don't require `reflect-metadata` module to be provided ([#15569](https://github.com/angular/angular/issues/15569)) ([bfa4f70](https://github.com/angular/angular/commit/bfa4f70)), closes [#15568](https://github.com/angular/angular/issues/15568)
* **language-service:** guard access to `Symbol.members` ([#15529](https://github.com/angular/angular/issues/15529)) ([bf25e94](https://github.com/angular/angular/commit/bf25e94)), closes [#15528](https://github.com/angular/angular/issues/15528)
* **language-service:** improve performance of `updateModuleAnalysis()` ([#15543](https://github.com/angular/angular/issues/15543)) ([5597fd3](https://github.com/angular/angular/commit/5597fd3))
* **router:** should run CanActivate after CanDeactivate guards ([75478b2](https://github.com/angular/angular/commit/75478b2)), closes [#14059](https://github.com/angular/angular/issues/14059) [#15467](https://github.com/angular/angular/issues/15467)
* **router:** shouldn't execute CanLoad when a route has been loaded ([2360676](https://github.com/angular/angular/commit/2360676)), closes [#14475](https://github.com/angular/angular/issues/14475) [#15438](https://github.com/angular/angular/issues/15438)
### Performance Improvements
* **router:** don't create new serializer every time UrlTree.toString is called ([#15565](https://github.com/angular/angular/issues/15565)) ([fd61145](https://github.com/angular/angular/commit/fd61145))
<a name="4.0.0"></a>
# [4.0.0](https://github.com/angular/angular/compare/4.0.0-rc.6...4.0.0) invisible-makeover (2017-03-23)

View File

@ -472,8 +472,9 @@ do
rsync -a ${OUT_DIR}/ ${NPM_DIR}
fi
echo "====== Copy ${PACKAGE} package.json files"
echo "====== Copy ${PACKAGE} package.json and .externs.js files"
rsync -am --include="package.json" --include="*/" --exclude=* ${SRC_DIR}/ ${NPM_DIR}/
rsync -am --include="*.externs.js" --include="*/" --exclude=* ${SRC_DIR}/ ${NPM_DIR}/
cp ${ROOT_DIR}/README.md ${NPM_DIR}/
fi

View File

@ -34,7 +34,7 @@ CLOSURE_ARGS=(
# Uncomment for easier debugging
# "--formatting=PRETTY_PRINT"
e2e/testability.externs.js
node_modules/@angular/core/src/testability/testability.externs.js
node_modules/zone.js/dist/zone.js
$(find -L vendor/rxjs -name *.js)
node_modules/@angular/core/@angular/core.js

View File

@ -1,47 +0,0 @@
/** @externs */
// Workaround for #11119
// TODO(alexeagle): these externs ought to be distributed with Angular.
/**
* @externs
* @suppress {duplicate}
*/
// NOTE: generated by tsickle, do not edit.
/** @record @struct */
function BrowserNodeGlobal() {}
/** @type {?} */
BrowserNodeGlobal.prototype.getAngularTestability;
/** @type {?} */
BrowserNodeGlobal.prototype.getAllAngularTestabilities;
/** @type {?} */
BrowserNodeGlobal.prototype.getAllAngularRootElements;
/** @type {?} */
BrowserNodeGlobal.prototype.frameworkStabilizers;
/**
* @param {?} condition
* @return {?}
*/
BrowserNodeGlobal.prototype.assert = function(condition) {};
/** @record @struct */
function PublicTestability() {}
/**
* @return {?}
*/
PublicTestability.prototype.isStable = function() {};
/**
* @param {?} callback
* @return {?}
*/
PublicTestability.prototype.whenStable = function(callback) {};
/**
* @param {?} using
* @param {?} provider
* @param {?} exactMatch
* @return {?}
*/
PublicTestability.prototype.findProviders = function(using, provider, exactMatch) {};

View File

@ -0,0 +1,81 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {$} from 'protractor';
export const CreateBtn = '#createDom';
export const DestroyBtn = '#destroyDom';
export const DetectChangesBtn = '#detectChanges';
export const RootEl = '#root';
export const NumberOfChecksEl = '#numberOfChecks';
export interface Benchmark {
id: string;
url: string;
buttons: string[];
ignoreBrowserSynchronization?: boolean;
extraParams?: {name: string, value: any}[];
}
const CreateDestroyButtons: string[] = [CreateBtn, DestroyBtn];
const CreateDestroyDetectChangesButtons: string[] = [...CreateDestroyButtons, DetectChangesBtn];
export const Benchmarks: Benchmark[] = [
{
id: `deepTree.ng2`,
url: 'all/benchmarks/src/tree/ng2/index.html',
buttons: CreateDestroyDetectChangesButtons,
},
{
id: `deepTree.ng2.next`,
url: 'all/benchmarks/src/tree/ng2_next/index.html',
buttons: CreateDestroyDetectChangesButtons,
ignoreBrowserSynchronization: true,
// Can't use bundles as we use non exported code
extraParams: [{name: 'bundles', value: false}]
},
{
id: `deepTree.ng2.static`,
url: 'all/benchmarks/src/tree/ng2_static/index.html',
buttons: CreateDestroyButtons,
},
{
id: `deepTree.ng2_switch`,
url: 'all/benchmarks/src/tree/ng2_switch/index.html',
buttons: CreateDestroyButtons,
},
{
id: `deepTree.baseline`,
url: 'all/benchmarks/src/tree/baseline/index.html',
buttons: CreateDestroyButtons,
ignoreBrowserSynchronization: true,
},
{
id: `deepTree.incremental_dom`,
url: 'all/benchmarks/src/tree/incremental_dom/index.html',
buttons: CreateDestroyButtons,
ignoreBrowserSynchronization: true,
},
{
id: `deepTree.polymer`,
url: 'all/benchmarks/src/tree/polymer/index.html',
buttons: CreateDestroyButtons,
ignoreBrowserSynchronization: true,
},
{
id: `deepTree.polymer_leaves`,
url: 'all/benchmarks/src/tree/polymer_leaves/index.html',
buttons: CreateDestroyButtons,
ignoreBrowserSynchronization: true,
},
{
id: `deepTree.ng1`,
url: 'all/benchmarks/src/tree/ng1/index.html',
buttons: CreateDestroyDetectChangesButtons,
}
];

View File

@ -7,162 +7,77 @@
*/
import {runBenchmark, verifyNoBrowserErrors} from 'e2e_util/perf_util';
import {$} from 'protractor';
import {$, browser} from 'protractor';
interface Worker {
id: string;
prepare?(): void;
work(): void;
}
const CreateOnlyWorker: Worker = {
id: 'createOnly',
prepare: () => $('#destroyDom').click(),
work: () => $('#createDom').click()
};
const CreateAndDestroyWorker: Worker = {
id: 'createDestroy',
work: () => {
$('#createDom').click();
$('#destroyDom').click();
}
};
const UpdateWorker: Worker = {
id: 'update',
work: () => $('#createDom').click()
};
import {Benchmark, Benchmarks, CreateBtn, DestroyBtn, DetectChangesBtn, RootEl} from './tree_data';
describe('tree benchmark perf', () => {
afterEach(verifyNoBrowserErrors);
let _oldRootEl: any;
beforeEach(() => _oldRootEl = browser.rootEl);
[CreateOnlyWorker, CreateAndDestroyWorker, UpdateWorker].forEach((worker) => {
describe(worker.id, () => {
afterEach(() => {
browser.rootEl = _oldRootEl;
verifyNoBrowserErrors();
});
it('should run for ng2', (done) => {
Benchmarks.forEach(benchmark => {
describe(benchmark.id, () => {
it('should work for createOnly', (done) => {
runTreeBenchmark({
id: `deepTree.ng2.${worker.id}`,
url: 'all/benchmarks/src/tree/ng2/index.html',
work: worker.work,
prepare: worker.prepare,
id: 'createOnly',
benchmark,
prepare: () => $(CreateBtn).click(),
work: () => $(DestroyBtn).click()
}).then(done, done.fail);
});
it('should run for ng2 next', (done) => {
it('should work for createDestroy', (done) => {
runTreeBenchmark({
id: `deepTree.ng2.next.${worker.id}`,
url: 'all/benchmarks/src/tree/ng2_next/index.html',
ignoreBrowserSynchronization: true,
work: worker.work,
prepare: worker.prepare,
// Can't use bundles as we use non exported code
extraParams: [{name: 'bundles', value: false}]
id: 'createDestroy',
benchmark,
work: () => {
$(DestroyBtn).click();
$(CreateBtn).click();
}
}).then(done, done.fail);
});
it('should run for ng2 static', (done) => {
runTreeBenchmark({
id: `deepTree.ng2.static.${worker.id}`,
url: 'all/benchmarks/src/tree/ng2_static/index.html',
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
it('should work for update', (done) => {
runTreeBenchmark({id: 'update', benchmark, work: () => $(CreateBtn).click()})
.then(done, done.fail);
});
it('should run for ng2 switch', (done) => {
runTreeBenchmark({
id: `deepTree.ng2_switch.${worker.id}`,
url: 'all/benchmarks/src/tree/ng2_switch/index.html',
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
if (benchmark.buttons.indexOf(DetectChangesBtn) !== -1) {
it('should work for detectChanges', (done) => {
runTreeBenchmark({
id: 'detectChanges',
benchmark,
work: () => $(DetectChangesBtn).click(),
setup: () => $(DestroyBtn).click()
}).then(done, done.fail);
});
}
it('should run for the baseline', (done) => {
runTreeBenchmark({
id: `deepTree.baseline.${worker.id}`,
url: 'all/benchmarks/src/tree/baseline/index.html',
ignoreBrowserSynchronization: true,
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
it('should run for incremental-dom', (done) => {
runTreeBenchmark({
id: `deepTree.incremental_dom.${worker.id}`,
url: 'all/benchmarks/src/tree/incremental_dom/index.html',
ignoreBrowserSynchronization: true,
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
it('should run for polymer binary tree', (done) => {
runTreeBenchmark({
id: `deepTree.polymer.${worker.id}`,
url: 'all/benchmarks/src/tree/polymer/index.html',
ignoreBrowserSynchronization: true,
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
it('should run for polymer leaves', (done) => {
runTreeBenchmark({
id: `deepTree.polymer_leaves.${worker.id}`,
url: 'all/benchmarks/src/tree/polymer_leaves/index.html',
ignoreBrowserSynchronization: true,
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
});
});
it('should run ng2 changedetection', (done) => {
runTreeBenchmark({
id: `deepTree.ng2.changedetection`,
url: 'all/benchmarks/src/tree/ng2/index.html',
work: () => $('#detectChanges').click(),
setup: () => $('#createDom').click(),
}).then(done, done.fail);
});
it('should run ng2 next changedetection', (done) => {
runTreeBenchmark({
id: `deepTree.ng2.next.changedetection`,
url: 'all/benchmarks/src/tree/ng2_next/index.html',
work: () => $('#detectChanges').click(),
setup: () => $('#createDom').click(),
ignoreBrowserSynchronization: true,
// Can't use bundles as we use non exported code
extraParams: [{name: 'bundles', value: false}]
}).then(done, done.fail);
});
function runTreeBenchmark(config: {
id: string,
url: string, ignoreBrowserSynchronization?: boolean,
work: () => any,
prepare?: () => any,
extraParams?: {name: string, value: any}[],
setup?: () => any
}) {
let params = [{name: 'depth', value: 11}];
if (config.extraParams) {
params = params.concat(config.extraParams);
}
return runBenchmark({
id: config.id,
url: config.url,
ignoreBrowserSynchronization: config.ignoreBrowserSynchronization,
params: params,
work: config.work,
prepare: config.prepare,
setup: config.setup
});
}
});
function runTreeBenchmark({id, benchmark, prepare, setup, work}: {
id: string; benchmark: Benchmark, prepare ? () : void; setup ? () : void; work(): void;
}) {
let params = [{name: 'depth', value: 11}];
if (benchmark.extraParams) {
params = params.concat(benchmark.extraParams);
}
browser.rootEl = RootEl;
return runBenchmark({
id: `${benchmark.id}.${id}`,
url: benchmark.url,
ignoreBrowserSynchronization: benchmark.ignoreBrowserSynchronization,
params: params,
work: work,
prepare: prepare,
setup: setup
});
}

View File

@ -7,107 +7,57 @@
*/
import {openBrowser, verifyNoBrowserErrors} from 'e2e_util/e2e_util';
import {$} from 'protractor';
import {$, browser} from 'protractor';
import {Benchmark, Benchmarks, CreateBtn, DestroyBtn, DetectChangesBtn, NumberOfChecksEl, RootEl} from './tree_data';
describe('tree benchmark spec', () => {
afterEach(verifyNoBrowserErrors);
let _oldRootEl: any;
beforeEach(() => _oldRootEl = browser.rootEl);
it('should work for ng2', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/ng2/index.html',
afterEach(() => {
browser.rootEl = _oldRootEl;
verifyNoBrowserErrors();
});
Benchmarks.forEach(benchmark => {
describe(benchmark.id, () => {
it('should work for createDestroy', () => {
openTreeBenchmark(benchmark);
$(CreateBtn).click();
expect($(RootEl).getText()).toContain('0');
$(DestroyBtn).click();
expect($(RootEl).getText()).toEqual('');
});
it('should work for update', () => {
openTreeBenchmark(benchmark);
$(CreateBtn).click();
$(CreateBtn).click();
expect($(RootEl).getText()).toContain('A');
});
if (benchmark.buttons.indexOf(DetectChangesBtn) !== -1) {
it('should work for detectChanges', () => {
openTreeBenchmark(benchmark);
$(DetectChangesBtn).click();
expect($(NumberOfChecksEl).getText()).toContain('10');
});
}
});
});
it('should work for ng2 detect changes', () => {
function openTreeBenchmark(benchmark: Benchmark) {
let params = [{name: 'depth', value: 4}];
openBrowser({url: 'all/benchmarks/src/tree/ng2/index.html', params});
$('#detectChanges').click();
expect($('#numberOfChecks').getText()).toContain('10');
});
it('should work for ng2 next', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/ng2_next/index.html',
ignoreBrowserSynchronization: true,
// Can't use bundles as we use non exported code
extraParams: [{name: 'bundles', value: false}]
});
});
it('should work for ng2 next detect changes', () => {
let params = [
{name: 'depth', value: 4},
// Can't use bundles as we use non exported code
{name: 'bundles', value: false}
];
openBrowser({
url: 'all/benchmarks/src/tree/ng2_next/index.html',
ignoreBrowserSynchronization: true, params
});
$('#detectChanges').click();
expect($('#numberOfChecks').getText()).toContain('10');
});
it('should work for ng2 static', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/ng2_static/index.html',
});
});
it('should work for ng2 switch', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/ng2_switch/index.html',
});
});
it('should work for the baseline', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/baseline/index.html',
ignoreBrowserSynchronization: true,
});
});
it('should work for incremental dom', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/incremental_dom/index.html',
ignoreBrowserSynchronization: true,
});
});
it('should work for polymer binary tree', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/polymer/index.html',
ignoreBrowserSynchronization: true,
});
});
it('should work for polymer leaves', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/polymer_leaves/index.html',
ignoreBrowserSynchronization: true,
});
});
function testTreeBenchmark(openConfig: {
url: string,
ignoreBrowserSynchronization?: boolean,
extraParams?: {name: string, value: any}[]
}) {
let params = [{name: 'depth', value: 4}];
if (openConfig.extraParams) {
params = params.concat(openConfig.extraParams);
if (benchmark.extraParams) {
params = params.concat(benchmark.extraParams);
}
browser.rootEl = RootEl;
openBrowser({
url: openConfig.url,
ignoreBrowserSynchronization: openConfig.ignoreBrowserSynchronization,
url: benchmark.url,
ignoreBrowserSynchronization: benchmark.ignoreBrowserSynchronization,
params: params,
});
$('#createDom').click();
expect($('#root').getText()).toContain('0');
$('#createDom').click();
expect($('#root').getText()).toContain('A');
$('#destroyDom').click();
expect($('#root').getText()).toEqual('');
}
});

View File

@ -0,0 +1,44 @@
<!doctype html>
<html>
<body>
<h2>Params</h2>
<form>
Depth:
<input type="number" name="depth" placeholder="depth" value="9">
<br>
<button>Apply</button>
</form>
<h2>Ng1 Tree Benchmark</h2>
<p>
<button id="destroyDom">destroyDom</button>
<button id="createDom">createDom</button>
<button id="detectChanges">detectChanges</button>
<button id="updateDomProfile">profile updateDom</button>
<button id="createDomProfile">profile createDom</button>
<button id="detectChangesProfile">profile detectChanges</button>
</p>
<div>
Change detection runs:<span id="numberOfChecks"></span>
</div>
<div>
<tree id="root" data="initData">Loading...</tree>
</div>
<script>
var mainUrls = [
'/all/benchmarks/vendor/angular.js',
'../../bootstrap_plain.js'
];
var mainUrl = window.location.search.split(/[?&]main=([^&]+)/)[1];
if (mainUrl) {
mainUrls = [mainUrl];
}
mainUrls.forEach(function(mainUrl) {
document.write('<script src="' + mainUrl + '">\u003c/script>');
});
</script>
</body>
</html>

View File

@ -0,0 +1,53 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {bindAction, profile} from '../../util';
import {buildTree, emptyTree} from '../util';
import {addTreeToModule} from './tree';
declare var angular: any;
function init() {
let detectChangesRuns = 0;
const numberOfChecksEl = document.getElementById('numberOfChecks') !;
addTreeToModule(angular.module('app', [])).run([
'$rootScope',
($rootScope: any) => {
function detectChanges() {
for (let i = 0; i < 10; i++) {
$rootScope.$digest();
}
detectChangesRuns += 10;
numberOfChecksEl.textContent = `${detectChangesRuns}`;
}
function noop() {}
function destroyDom() {
$rootScope.$apply(() => { $rootScope.initData = emptyTree; });
}
function createDom() {
$rootScope.$apply(() => { $rootScope.initData = buildTree(); });
}
bindAction('#destroyDom', destroyDom);
bindAction('#createDom', createDom);
bindAction('#detectChanges', detectChanges);
bindAction('#detectChangesProfile', profile(detectChanges, noop, 'detectChanges'));
bindAction('#updateDomProfile', profile(createDom, noop, 'update'));
bindAction('#createDomProfile', profile(createDom, destroyDom, 'create'));
}
]);
angular.bootstrap(document.querySelector('tree'), ['app']);
}
init();

View File

@ -0,0 +1,72 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {TreeNode} from '../util';
declare var angular: any;
export function addTreeToModule(mod: any): any {
return mod
.directive(
'tree',
function() {
return {
scope: {data: '='},
template:
`<span ng-style="{'background-color': data.depth % 2 ? '' : 'grey'}"> {{data.value}} </span><tree-if data='data.right'></tree-if><tree-if data='data.left'></tree-if>`
};
})
// special directive for "if" as angular 1.3 does not support
// recursive components.
// Cloned from real ngIf directive, but using a lazily created transclude function.
.directive(
'treeIf',
[
'$compile', '$animate',
function($compile: any, $animate: any) {
let transcludeFn: any;
return {
transclude: 'element',
priority: 600,
terminal: true,
$$tlb: true,
link: function($scope: any, $element: any, $attr: any, ctrl: any) {
if (!transcludeFn) {
const template = '<tree data="' + $attr.data + '"></tree>';
transcludeFn = $compile(template);
}
let childElement: any, childScope: any;
$scope.$watch($attr.data, function ngIfWatchAction(value: any) {
if (value) {
if (!childScope) {
childScope = $scope.$new();
transcludeFn(childScope, function(clone: any) {
childElement = clone;
$animate.enter(clone, $element.parent(), $element);
});
}
} else {
if (childScope) {
childScope.$destroy();
childScope = null;
}
if (childElement) {
$animate.leave(childElement);
childElement = null;
}
}
});
}
};
}
])
.config([
'$compileProvider',
function($compileProvider: any) { $compileProvider.debugInfoEnabled(false); }
]);
}

View File

@ -40,7 +40,7 @@ export function init(moduleRef: NgModuleRef<AppModule>) {
const injector = moduleRef.injector;
appRef = injector.get(ApplicationRef);
const numberOfChecksEl = document.getElementById('numberOfChecks');
const numberOfChecksEl = document.getElementById('numberOfChecks') !;
tree = appRef.components[0].instance;

View File

@ -13,10 +13,10 @@ export class TreeNode {
children: TreeNode[];
constructor(
public value: string, public depth: number, public maxDepth: number, public left: TreeNode,
public right: TreeNode) {
public value: string, public depth: number, public maxDepth: number,
public left: TreeNode|null, public right: TreeNode|null) {
this.transitiveChildCount = Math.pow(2, (this.maxDepth - this.depth + 1)) - 1;
this.children = this.left ? [this.left, this.right] : [];
this.children = this.left ? [this.left, this.right !] : [];
}
// Needed for Polymer as it does not support ternary nor modulo operator

View File

@ -35,7 +35,7 @@ export function getStringParameter(name: string) {
}
export function bindAction(selector: string, callback: () => void) {
document.querySelector(selector).addEventListener('click', callback);
document.querySelector(selector) !.addEventListener('click', callback);
}
@ -60,7 +60,7 @@ export function profile(create: () => void, destroy: () => void, name: string) {
function urlParamsToForm() {
const regex = /(\w+)=(\w+)/g;
const search = decodeURIComponent(location.search);
let match: any[];
let match: any[]|null;
while (match = regex.exec(search)) {
const name = match[1];
const value = match[2];
@ -75,4 +75,4 @@ function urlParamsToForm() {
}
}
}
}
}

View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "4.0.0-rc.5",
"version": "4.1.0-beta.1",
"dependencies": {
"@types/angularjs": {
"version": "1.5.13-alpha",
@ -86,6 +86,10 @@
}
}
},
"ajv": {
"version": "4.11.7",
"dev": true
},
"align-text": {
"version": "0.1.3",
"dev": true,
@ -2025,6 +2029,10 @@
}
}
},
"co": {
"version": "4.6.0",
"dev": true
},
"code-point-at": {
"version": "1.0.0",
"dev": true
@ -3793,6 +3801,10 @@
}
}
},
"har-schema": {
"version": "1.0.5",
"dev": true
},
"har-validator": {
"version": "2.0.6",
"dev": true,
@ -4219,6 +4231,10 @@
"version": "0.2.3",
"dev": true
},
"json-stable-stringify": {
"version": "1.0.1",
"dev": true
},
"json-stringify-safe": {
"version": "5.0.1",
"dev": true
@ -4235,6 +4251,10 @@
"version": "2.2.3",
"dev": true
},
"jsonify": {
"version": "0.0.0",
"dev": true
},
"jsonparse": {
"version": "1.2.0",
"dev": true
@ -5170,6 +5190,10 @@
"version": "0.9.0",
"dev": true
},
"performance-now": {
"version": "0.2.0",
"dev": true
},
"pify": {
"version": "2.3.0",
"dev": true
@ -5225,39 +5249,51 @@
}
},
"protractor": {
"version": "4.0.11",
"version": "4.0.14",
"dev": true,
"dependencies": {
"@types/jasmine": {
"version": "2.5.37",
"version": "2.5.47",
"dev": true
},
"@types/node": {
"version": "6.0.46",
"version": "6.0.68",
"dev": true
},
"@types/selenium-webdriver": {
"version": "2.53.37",
"dev": true
},
"caseless": {
"version": "0.12.0",
"dev": true
},
"glob": {
"version": "7.1.1",
"dev": true
},
"har-validator": {
"version": "4.2.1",
"dev": true
},
"mime-db": {
"version": "1.24.0",
"version": "1.27.0",
"dev": true
},
"mime-types": {
"version": "2.1.12",
"version": "2.1.15",
"dev": true
},
"qs": {
"version": "6.3.0",
"version": "6.4.0",
"dev": true
},
"request": {
"version": "2.78.0",
"version": "2.81.0",
"dev": true
},
"rimraf": {
"version": "2.5.4",
"version": "2.6.1",
"dev": true
},
"saucelabs": {
@ -5272,8 +5308,16 @@
"version": "2.3.2",
"dev": true
},
"tunnel-agent": {
"version": "0.6.0",
"dev": true
},
"uuid": {
"version": "3.0.1",
"dev": true
},
"webdriver-manager": {
"version": "10.2.8",
"version": "10.3.0",
"dev": true
}
}
@ -5604,6 +5648,10 @@
"rxjs": {
"version": "5.0.1"
},
"safe-buffer": {
"version": "5.0.1",
"dev": true
},
"sander": {
"version": "0.5.1",
"dev": true,

118
npm-shrinkwrap.json generated
View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "4.0.0-rc.5",
"version": "4.1.0-beta.1",
"dependencies": {
"@types/angularjs": {
"version": "1.5.13-alpha",
@ -126,6 +126,12 @@
}
}
},
"ajv": {
"version": "4.11.7",
"from": "ajv@>=4.9.1 <5.0.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.7.tgz",
"dev": true
},
"align-text": {
"version": "0.1.3",
"from": "align-text@>=0.1.0 <0.2.0",
@ -2911,6 +2917,12 @@
}
}
},
"co": {
"version": "4.6.0",
"from": "co@>=4.6.0 <5.0.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"dev": true
},
"code-point-at": {
"version": "1.0.0",
"from": "code-point-at@>=1.0.0 <2.0.0",
@ -5529,6 +5541,12 @@
}
}
},
"har-schema": {
"version": "1.0.5",
"from": "har-schema@>=1.0.5 <2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
"dev": true
},
"har-validator": {
"version": "2.0.6",
"from": "har-validator@>=2.0.6 <2.1.0",
@ -6159,6 +6177,12 @@
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"dev": true
},
"json-stable-stringify": {
"version": "1.0.1",
"from": "json-stable-stringify@>=1.0.1 <2.0.0",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
"dev": true
},
"json-stringify-safe": {
"version": "5.0.1",
"from": "json-stringify-safe@>=5.0.1 <5.1.0",
@ -6183,6 +6207,12 @@
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.2.3.tgz",
"dev": true
},
"jsonify": {
"version": "0.0.0",
"from": "jsonify@>=0.0.0 <0.1.0",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
"dev": true
},
"jsonparse": {
"version": "1.2.0",
"from": "jsonparse@>=1.1.0 <2.0.0",
@ -7554,6 +7584,12 @@
"resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.9.0.tgz",
"dev": true
},
"performance-now": {
"version": "0.2.0",
"from": "performance-now@>=0.2.0 <0.3.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
"dev": true
},
"pify": {
"version": "2.3.0",
"from": "pify@>=2.0.0 <3.0.0",
@ -7635,21 +7671,33 @@
}
},
"protractor": {
"version": "4.0.11",
"from": "protractor@4.0.11",
"resolved": "https://registry.npmjs.org/protractor/-/protractor-4.0.11.tgz",
"version": "4.0.14",
"from": "protractor@4.0.14",
"resolved": "https://registry.npmjs.org/protractor/-/protractor-4.0.14.tgz",
"dev": true,
"dependencies": {
"@types/jasmine": {
"version": "2.5.37",
"version": "2.5.47",
"from": "@types/jasmine@>=2.5.36 <3.0.0",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.37.tgz",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.47.tgz",
"dev": true
},
"@types/node": {
"version": "6.0.46",
"version": "6.0.68",
"from": "@types/node@>=6.0.46 <7.0.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.46.tgz",
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.68.tgz",
"dev": true
},
"@types/selenium-webdriver": {
"version": "2.53.37",
"from": "@types/selenium-webdriver@2.53.37",
"resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.37.tgz",
"dev": true
},
"caseless": {
"version": "0.12.0",
"from": "caseless@>=0.12.0 <0.13.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"dev": true
},
"glob": {
@ -7658,34 +7706,40 @@
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz",
"dev": true
},
"har-validator": {
"version": "4.2.1",
"from": "har-validator@>=4.2.1 <4.3.0",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
"dev": true
},
"mime-db": {
"version": "1.24.0",
"from": "mime-db@~1.24.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.24.0.tgz",
"version": "1.27.0",
"from": "mime-db@>=1.27.0 <1.28.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz",
"dev": true
},
"mime-types": {
"version": "2.1.12",
"version": "2.1.15",
"from": "mime-types@>=2.1.7 <2.2.0",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.12.tgz",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz",
"dev": true
},
"qs": {
"version": "6.3.0",
"from": "qs@>=6.3.0 <6.4.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.3.0.tgz",
"version": "6.4.0",
"from": "qs@>=6.4.0 <6.5.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
"dev": true
},
"request": {
"version": "2.78.0",
"version": "2.81.0",
"from": "request@>=2.78.0 <3.0.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.78.0.tgz",
"resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
"dev": true
},
"rimraf": {
"version": "2.5.4",
"version": "2.6.1",
"from": "rimraf@>=2.5.2 <3.0.0",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz",
"dev": true
},
"saucelabs": {
@ -7706,10 +7760,22 @@
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
"dev": true
},
"tunnel-agent": {
"version": "0.6.0",
"from": "tunnel-agent@>=0.6.0 <0.7.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"dev": true
},
"uuid": {
"version": "3.0.1",
"from": "uuid@>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz",
"dev": true
},
"webdriver-manager": {
"version": "10.2.8",
"from": "webdriver-manager@>=10.2.8 <11.0.0",
"resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-10.2.8.tgz",
"version": "10.3.0",
"from": "webdriver-manager@>=10.3.0 <11.0.0",
"resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-10.3.0.tgz",
"dev": true
}
}
@ -8196,6 +8262,12 @@
"from": "rxjs@5.0.1",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.0.1.tgz"
},
"safe-buffer": {
"version": "5.0.1",
"from": "safe-buffer@>=5.0.1 <6.0.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
"dev": true
},
"sander": {
"version": "0.5.1",
"from": "sander@>=0.5.0 <0.6.0",

View File

@ -1,6 +1,6 @@
{
"name": "angular-srcs",
"version": "4.0.0",
"version": "4.0.3",
"private": true,
"branchPattern": "2.0.*",
"description": "Angular - a web framework for modern web apps",
@ -77,7 +77,7 @@
"nan": "^2.4.0",
"node-uuid": "1.4.x",
"parse5": "^3.0.1",
"protractor": "^4.0.11",
"protractor": "^4.0.14",
"react": "^0.14.0",
"rewire": "^2.3.3",
"rho": "^0.3.0",

View File

@ -13,3 +13,4 @@ export {NoopAnimationDriver as ɵNoopAnimationDriver} from './render/animation_d
export {DomAnimationEngine as ɵDomAnimationEngine} from './render/dom_animation_engine';
export {NoopAnimationEngine as ɵNoopAnimationEngine} from './render/noop_animation_engine';
export {WebAnimationsDriver as ɵWebAnimationsDriver, supportsWebAnimations as ɵsupportsWebAnimations} from './render/web_animations/web_animations_driver';
export {WebAnimationsPlayer as ɵWebAnimationsPlayer} from './render/web_animations/web_animations_player';

View File

@ -259,8 +259,6 @@ export class DomAnimationEngine {
const player = this._buildPlayer(element, instruction, previousPlayers, i);
player.onDestroy(
() => { deleteFromArrayMap(this._activeElementAnimations, element, player); });
player.init();
this._markPlayerAsActive(element, player);
return player;
});
@ -354,6 +352,7 @@ export class DomAnimationEngine {
// in the event that an animation throws an error then we do
// not want to re-run animations on any previous animations
// if they have already been kicked off beforehand
player.init();
if (!player.hasStarted()) {
player.play();
}

View File

@ -87,6 +87,22 @@ export function main() {
expect(engine.queuedPlayers.pop() instanceof NoopAnimationPlayer).toBe(true);
});
it('should not initialize the animation until the engine has been flushed', () => {
const engine = makeEngine();
engine.registerTrigger(trigger(
'trig', [transition('* => something', [animate(1000, style({color: 'gold'}))])]));
engine.setProperty(element, 'trig', 'something');
const player = engine.queuedPlayers.pop() as MockAnimationPlayer;
let initialized = false;
player.onInit(() => initialized = true);
expect(initialized).toBe(false);
engine.flush();
expect(initialized).toBe(true);
});
it('should not queue an animation if the property value has not changed at all', () => {
const engine = makeEngine();

View File

@ -31,6 +31,7 @@ export class MockAnimationDriver implements AnimationDriver {
export class MockAnimationPlayer extends NoopAnimationPlayer {
private __finished = false;
public previousStyles: {[key: string]: string | number} = {};
private _onInitFns: (() => any)[] = [];
constructor(
public element: any, public keyframes: {[key: string]: string | number}[],
@ -45,6 +46,16 @@ export class MockAnimationPlayer extends NoopAnimationPlayer {
});
}
/* @internal */
onInit(fn: () => any) { this._onInitFns.push(fn); }
/* @internal */
init() {
super.init();
this._onInitFns.forEach(fn => fn());
this._onInitFns = [];
}
finish(): void {
super.finish();
this.__finished = true;

View File

@ -98,7 +98,7 @@ export interface AnimationStyleMetadata extends AnimationMetadata {
*/
export interface AnimationAnimateMetadata extends AnimationMetadata {
timings: string|number|AnimateTimings;
styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata;
styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata|null;
}
/**
@ -118,10 +118,10 @@ export interface AnimationSequenceMetadata extends AnimationMetadata { steps: An
export interface AnimationGroupMetadata extends AnimationMetadata { steps: AnimationMetadata[]; }
/**
* `trigger` is an animation-specific function that is designed to be used inside of Angular2's
* `trigger` is an animation-specific function that is designed to be used inside of Angular's
animation DSL language. If this information is new, please navigate to the {@link
Component#animations-anchor component animations metadata page} to gain a better understanding of
how animations in Angular2 are used.
how animations in Angular are used.
*
* `trigger` Creates an animation trigger which will a list of {@link state state} and {@link
transition transition} entries that will be evaluated when the expression bound to the trigger
@ -173,10 +173,10 @@ export function trigger(name: string, definitions: AnimationMetadata[]): Animati
}
/**
* `animate` is an animation-specific function that is designed to be used inside of Angular2's
* `animate` is an animation-specific function that is designed to be used inside of Angular's
* animation DSL language. If this information is new, please navigate to the {@link
* Component#animations-anchor component animations metadata page} to gain a better understanding of
* how animations in Angular2 are used.
* how animations in Angular are used.
*
* `animate` specifies an animation step that will apply the provided `styles` data for a given
* amount of time based on the provided `timing` expression value. Calls to `animate` are expected
@ -218,16 +218,16 @@ export function trigger(name: string, definitions: AnimationMetadata[]): Animati
* @experimental Animation support is experimental.
*/
export function animate(
timings: string | number, styles: AnimationStyleMetadata | AnimationKeyframesSequenceMetadata =
null): AnimationAnimateMetadata {
timings: string | number, styles: AnimationStyleMetadata | AnimationKeyframesSequenceMetadata |
null = null): AnimationAnimateMetadata {
return {type: AnimationMetadataType.Animate, styles: styles, timings: timings};
}
/**
* `group` is an animation-specific function that is designed to be used inside of Angular2's
* `group` is an animation-specific function that is designed to be used inside of Angular's
* animation DSL language. If this information is new, please navigate to the {@link
* Component#animations-anchor component animations metadata page} to gain a better understanding of
* how animations in Angular2 are used.
* how animations in Angular are used.
*
* `group` specifies a list of animation steps that are all run in parallel. Grouped animations are
* useful when a series of styles must be animated/closed off at different statrting/ending times.
@ -259,10 +259,10 @@ export function group(steps: AnimationMetadata[]): AnimationGroupMetadata {
}
/**
* `sequence` is an animation-specific function that is designed to be used inside of Angular2's
* `sequence` is an animation-specific function that is designed to be used inside of Angular's
* animation DSL language. If this information is new, please navigate to the {@link
* Component#animations-anchor component animations metadata page} to gain a better understanding of
* how animations in Angular2 are used.
* how animations in Angular are used.
*
* `sequence` Specifies a list of animation steps that are run one by one. (`sequence` is used by
* default when an array is passed as animation data into {@link transition transition}.)
@ -297,10 +297,10 @@ export function sequence(steps: AnimationMetadata[]): AnimationSequenceMetadata
}
/**
* `style` is an animation-specific function that is designed to be used inside of Angular2's
* `style` is an animation-specific function that is designed to be used inside of Angular's
* animation DSL language. If this information is new, please navigate to the {@link
* Component#animations-anchor component animations metadata page} to gain a better understanding of
* how animations in Angular2 are used.
* how animations in Angular are used.
*
* `style` declares a key/value object containing CSS properties/styles that can then be used for
* {@link state animation states}, within an {@link sequence animation sequence}, or as styling data
@ -345,10 +345,10 @@ export function style(
}
/**
* `state` is an animation-specific function that is designed to be used inside of Angular2's
* `state` is an animation-specific function that is designed to be used inside of Angular's
* animation DSL language. If this information is new, please navigate to the {@link
* Component#animations-anchor component animations metadata page} to gain a better understanding of
* how animations in Angular2 are used.
* how animations in Angular are used.
*
* `state` declares an animation state within the given trigger. When a state is active within a
* component then its associated styles will persist on the element that the trigger is attached to
@ -397,10 +397,10 @@ export function state(name: string, styles: AnimationStyleMetadata): AnimationSt
}
/**
* `keyframes` is an animation-specific function that is designed to be used inside of Angular2's
* `keyframes` is an animation-specific function that is designed to be used inside of Angular's
* animation DSL language. If this information is new, please navigate to the {@link
* Component#animations-anchor component animations metadata page} to gain a better understanding of
* how animations in Angular2 are used.
* how animations in Angular are used.
*
* `keyframes` specifies a collection of {@link style style} entries each optionally characterized
* by an `offset` value.
@ -446,10 +446,10 @@ export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSe
}
/**
* `transition` is an animation-specific function that is designed to be used inside of Angular2's
* `transition` is an animation-specific function that is designed to be used inside of Angular's
* animation DSL language. If this information is new, please navigate to the {@link
* Component#animations-anchor component animations metadata page} to gain a better understanding of
* how animations in Angular2 are used.
* how animations in Angular are used.
*
* `transition` declares the {@link sequence sequence of animation steps} that will be run when the
* provided `stateChangeExpr` value is satisfied. The `stateChangeExpr` consists of a `state1 =>

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
// Must be imported first, because angular2 decorators throws on load.
// Must be imported first, because Angular decorators throw on load.
import 'reflect-metadata';
export {InjectionToken, Injector, Provider, ReflectiveInjector} from '@angular/core';

View File

@ -24,6 +24,7 @@ export class ChromeDriverExtension extends WebDriverExtension {
static PROVIDERS = [ChromeDriverExtension];
private _majorChromeVersion: number;
private _firstRun = true;
constructor(private _driver: WebDriverAdapter, @Inject(Options.USER_AGENT) userAgent: string) {
super();
@ -48,6 +49,12 @@ export class ChromeDriverExtension extends WebDriverExtension {
gc() { return this._driver.executeScript('window.gc()'); }
timeBegin(name: string): Promise<any> {
if (this._firstRun) {
this._firstRun = false;
// Before the first run, read out the existing performance logs
// so that the chrome buffer does not fill up.
this._driver.logs('performance');
}
return this._driver.executeScript(`console.time('${name}');`);
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/src/testing_internal';
import {AsyncTestCompleter, describe, expect, iit, inject, it} from '@angular/core/testing/src/testing_internal';
import {ChromeDriverExtension, Options, ReflectiveInjector, WebDriverAdapter, WebDriverExtension} from '../../index';
import {TraceEventFactory} from '../trace_event_factory';
@ -61,14 +61,29 @@ export function main() {
});
}));
it('should mark the timeline via console.time()',
it('should clear the perf logs and mark the timeline via console.time() on the first call',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeBegin('someName').then((_) => {
expect(log).toEqual([['executeScript', `console.time('someName');`]]);
createExtension().timeBegin('someName').then(() => {
expect(log).toEqual(
[['logs', 'performance'], ['executeScript', `console.time('someName');`]]);
async.done();
});
}));
it('should mark the timeline via console.time() on the second call',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const ext = createExtension();
ext.timeBegin('someName')
.then((_) => {
log.splice(0, log.length);
ext.timeBegin('someName');
})
.then(() => {
expect(log).toEqual([['executeScript', `console.time('someName');`]]);
async.done();
});
}));
it('should mark the timeline via console.timeEnd()',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
createExtension().timeEnd('someName', null).then((_) => {

View File

@ -72,7 +72,7 @@ export class NgLocaleLocalization extends NgLocalization {
}
// This is generated code DO NOT MODIFY
// see angular2/script/cldr/gen_plural_rules.js
// see angular/script/cldr/gen_plural_rules.js
/** @experimental */
export enum Plural {

View File

@ -63,6 +63,33 @@ const EXPECTED_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
</xliff>
`;
const EXPECTED_XLIFF2 = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en">
<file original="ng.template" id="ngi18n">
<unit id="8136548302122759730">
<notes>
<note category="description">desc</note>
<note category="meaning">meaning</note>
</notes>
<segment>
<source>translate me</source>
</segment>
</unit>
<unit id="3492007542396725315">
<segment>
<source>Welcome</source>
</segment>
</unit>
<unit id="126808141597411718">
<segment>
<source>other-3rdP-component
multi-lines</source>
</segment>
</unit>
</file>
</xliff>
`;
describe('template i18n extraction output', () => {
const outDir = '';
const genDir = 'out';
@ -81,6 +108,13 @@ describe('template i18n extraction output', () => {
expect(xlf).toEqual(EXPECTED_XLIFF);
});
it('should extract i18n messages as xliff version 2.0', () => {
const xlfOutput = path.join(outDir, 'messages.xliff2.xlf');
expect(fs.existsSync(xlfOutput)).toBeTruthy();
const xlf = fs.readFileSync(xlfOutput, {encoding: 'utf-8'});
expect(xlf).toEqual(EXPECTED_XLIFF2);
});
it('should not emit js', () => {
const genOutput = path.join(genDir, '');
expect(fs.existsSync(genOutput)).toBeFalsy();

View File

@ -30,7 +30,7 @@ function getSourcePositionForStack(stack: string): {source: string, line: number
const htmlLocations = stack
.split('\n')
// e.g. at View_MyComp_0 (...html:153:40)
.map(line => /\((.*\.html):(\d+):(\d+)/.exec(line))
.map(line => /\((.*\.html):(\d+):(\d+)/.exec(line) !)
.filter(match => !!match)
.map(match => ({
source: match[1],

View File

@ -8,7 +8,7 @@
*/
/* tslint:disable:no-console */
// Must be imported first, because angular2 decorators throws on load.
// Must be imported first, because Angular decorators throw on load.
import 'reflect-metadata';
import * as path from 'path';
@ -67,9 +67,9 @@ function codeGenTest() {
angularCompilerOptions: config.ngOptions,
// i18n options.
i18nFormat: null,
i18nFile: null,
locale: null,
i18nFormat: undefined,
i18nFile: undefined,
locale: undefined,
readResource: (fileName: string) => {
readResources.push(fileName);
@ -131,8 +131,8 @@ function i18nTest() {
compilerOptions: config.parsed.options, program, host,
angularCompilerOptions: config.ngOptions,
i18nFormat: 'xlf',
locale: null,
outFile: null,
locale: undefined,
outFile: undefined,
readResource: (fileName: string) => {
readResources.push(fileName);
return hostContext.readResource(fileName);

View File

@ -8,7 +8,7 @@
*/
/* tslint:disable:no-console */
// Must be imported first, because angular2 decorators throws on load.
// Must be imported first, because Angular decorators throw on load.
import 'reflect-metadata';
import * as path from 'path';
@ -34,7 +34,8 @@ function main() {
if (/.*\/node_modules\/.*/.test(fileName) && !/.*ngsummary\.json$/.test(fileName) &&
!/package\.json$/.test(fileName)) {
// Only allow to read summaries and package.json files from node_modules
return null;
// TODO (mhevery): Fix this. TypeScript.d.ts does not allow returning null.
return null !;
}
readFiles.push(path.relative(basePath, fileName));
return super.readFile(fileName);

View File

@ -13,7 +13,7 @@ import {platformServer} from '@angular/platform-server';
import {MainModule} from '../src/module';
import {MainModuleNgFactory} from '../src/module.ngfactory';
let mainModuleRef: NgModuleRef<MainModule> = null;
let mainModuleRef: NgModuleRef<MainModule> = null !;
beforeEach((done) => {
platformServer().bootstrapModuleFactory(MainModuleNgFactory).then((moduleRef: any) => {
mainModuleRef = moduleRef;
@ -29,5 +29,5 @@ export function createComponent<C>(comp: {new (...args: any[]): C}): ComponentFi
const moduleRef = createModule();
const compRef =
moduleRef.componentFactoryResolver.resolveComponentFactory(comp).create(moduleRef.injector);
return new ComponentFixture(compRef, null, null);
return new ComponentFixture(compRef, null, false);
}

View File

@ -10,6 +10,8 @@
"target": "es5",
"experimentalDecorators": true,
"noImplicitAny": true,
"strictNullChecks": true,
"skipLibCheck": true,
"moduleResolution": "node",
"rootDir": "",
"declaration": true,
@ -32,4 +34,4 @@
"benchmarks/src/largetable/ng2/index_aot.ts",
"benchmarks/src/largetable/ng2_switch/index_aot.ts"
]
}
}

View File

@ -9,7 +9,7 @@
"ng-xi18n": "./src/extract_i18n.js"
},
"dependencies": {
"@angular/tsc-wrapped": "4.0.0",
"@angular/tsc-wrapped": "4.0.3",
"reflect-metadata": "^0.1.2",
"minimist": "^1.2.0"
},

View File

@ -24,7 +24,7 @@ const GENERATED_META_FILES = /\.json$/;
const PREAMBLE = `/**
* @fileoverview This file is generated by the Angular template compiler.
* Do not edit.
* @suppress {suspiciousCode,uselessCode,missingProperties}
* @suppress {suspiciousCode,uselessCode,missingProperties,missingOverride}
*/
/* tslint:disable */

View File

@ -33,6 +33,7 @@ export class CompilerHost implements AotCompilerHost {
private resolverCache = new Map<string, ModuleMetadata[]>();
private bundleIndexCache = new Map<string, boolean>();
private bundleIndexNames = new Set<string>();
private moduleFileNames = new Map<string, string>();
protected resolveModuleNameHost: CompilerHostContext;
constructor(
@ -69,19 +70,25 @@ export class CompilerHost implements AotCompilerHost {
getCanonicalFileName(fileName: string): string { return fileName; }
moduleNameToFileName(m: string, containingFile: string): string|null {
if (!containingFile || !containingFile.length) {
if (m.indexOf('.') === 0) {
throw new Error('Resolution of relative paths requires a containing file.');
const key = m + ':' + (containingFile || '');
let result = this.moduleFileNames.get(key);
if (!result) {
if (!containingFile || !containingFile.length) {
if (m.indexOf('.') === 0) {
throw new Error('Resolution of relative paths requires a containing file.');
}
// Any containing file gives the same result for absolute imports
containingFile = this.getCanonicalFileName(path.join(this.basePath, 'index.ts'));
}
// Any containing file gives the same result for absolute imports
containingFile = this.getCanonicalFileName(path.join(this.basePath, 'index.ts'));
m = m.replace(EXT, '');
const resolved =
ts.resolveModuleName(
m, containingFile.replace(/\\/g, '/'), this.options, this.resolveModuleNameHost)
.resolvedModule;
result = resolved ? this.getCanonicalFileName(resolved.resolvedFileName) : null;
this.moduleFileNames.set(key, result);
}
m = m.replace(EXT, '');
const resolved =
ts.resolveModuleName(
m, containingFile.replace(/\\/g, '/'), this.options, this.resolveModuleNameHost)
.resolvedModule;
return resolved ? this.getCanonicalFileName(resolved.resolvedFileName) : null;
return result;
};
/**

View File

@ -11,7 +11,7 @@
/**
* Extract i18n messages from source code
*/
// Must be imported first, because angular2 decorators throws on load.
// Must be imported first, because Angular decorators throw on load.
import 'reflect-metadata';
import * as tsc from '@angular/tsc-wrapped';

View File

@ -10,7 +10,7 @@
/**
* Extract i18n messages from source code
*/
// Must be imported first, because angular2 decorators throws on load.
// Must be imported first, because Angular decorators throw on load.
import 'reflect-metadata';
import * as compiler from '@angular/compiler';
@ -34,7 +34,7 @@ export class Extractor {
const promiseBundle = this.extractBundle();
return promiseBundle.then(bundle => {
const content = this.serialize(bundle, ext);
const content = this.serialize(bundle, formatName);
const dstFile = outFile || `messages.${ext}`;
const dstPath = path.join(this.options.genDir, dstFile);
this.host.writeFile(dstPath, content, false);
@ -48,14 +48,20 @@ export class Extractor {
return this.ngExtractor.extract(files);
}
serialize(bundle: compiler.MessageBundle, ext: string): string {
serialize(bundle: compiler.MessageBundle, formatName: string): string {
const format = formatName.toLowerCase();
let serializer: compiler.Serializer;
switch (ext) {
switch (format) {
case 'xmb':
serializer = new compiler.Xmb();
break;
case 'xliff2':
case 'xlf2':
serializer = new compiler.Xliff2();
break;
case 'xlf':
case 'xliff':
default:
serializer = new compiler.Xliff();
}
@ -66,10 +72,18 @@ export class Extractor {
getExtension(formatName: string): string {
const format = (formatName || 'xlf').toLowerCase();
if (format === 'xmb') return 'xmb';
if (format === 'xlf' || format === 'xlif' || format === 'xliff') return 'xlf';
switch (format) {
case 'xmb':
return 'xmb';
case 'xlf':
case 'xlif':
case 'xliff':
case 'xlf2':
case 'xliff2':
return 'xlf';
}
throw new Error('Unsupported format "${formatName}"');
throw new Error(`Unsupported format "${formatName}"`);
}
static create(

View File

@ -8,7 +8,7 @@
*/
// Must be imported first, because angular2 decorators throws on load.
// Must be imported first, because Angular decorators throw on load.
import 'reflect-metadata';
import * as ts from 'typescript';

View File

@ -32,9 +32,9 @@ export interface NgTools_InternalApi_NG2_CodeGen_Options {
angularCompilerOptions: AngularCompilerOptions;
// i18n options.
i18nFormat: string;
i18nFile: string;
locale: string;
i18nFormat?: string;
i18nFile?: string;
locale?: string;
readResource: (fileName: string) => Promise<string>;
@ -58,7 +58,7 @@ export interface NgTools_InternalApi_NG2_ExtractI18n_Options {
program: ts.Program;
host: ts.CompilerHost;
angularCompilerOptions: AngularCompilerOptions;
i18nFormat: string;
i18nFormat?: string;
readResource: (fileName: string) => Promise<string>;
// Every new property under this line should be optional.
locale?: string;
@ -124,7 +124,7 @@ export class NgTools_InternalApi_NG_2 {
const symbolCache = new StaticSymbolCache();
const summaryResolver = new AotSummaryResolver(ngCompilerHost, symbolCache);
const symbolResolver = new StaticSymbolResolver(ngCompilerHost, symbolCache, summaryResolver);
const staticReflector = new StaticReflector(symbolResolver);
const staticReflector = new StaticReflector(summaryResolver, symbolResolver);
const routeMap = listLazyRoutesOfModule(options.entryModule, ngCompilerHost, staticReflector);
return Object.keys(routeMap).reduce(

View File

@ -47,7 +47,7 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
const symbolCache = new StaticSymbolCache();
const summaryResolver = new AotSummaryResolver(compilerHost, symbolCache);
const symbolResolver = new StaticSymbolResolver(compilerHost, symbolCache, summaryResolver);
const staticReflector = new StaticReflector(symbolResolver);
const staticReflector = new StaticReflector(summaryResolver, symbolResolver);
StaticAndDynamicReflectionCapabilities.install(staticReflector);
const console = new Console();
const htmlParser = new I18NHtmlParser(

View File

@ -7,7 +7,11 @@
*/
import {Attribute, Component, ContentChild, ContentChildren, Directive, Host, HostBinding, HostListener, Inject, Injectable, Input, NgModule, Optional, Output, Pipe, Self, SkipSelf, ViewChild, ViewChildren, animate, group, keyframes, sequence, state, style, transition, trigger, ɵReflectorReader} from '@angular/core';
import {CompileSummaryKind} from '../compile_metadata';
import {SummaryResolver} from '../summary_resolver';
import {syntaxError} from '../util';
import {StaticSymbol} from './static_symbol';
import {StaticSymbolResolver} from './static_symbol_resolver';
@ -35,8 +39,11 @@ export class StaticReflector implements ɵReflectorReader {
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
private injectionToken: StaticSymbol;
private opaqueToken: StaticSymbol;
private annotationForParentClassWithSummaryKind = new Map<CompileSummaryKind, any[]>();
private annotationNames = new Map<any, string>();
constructor(
private summaryResolver: SummaryResolver<StaticSymbol>,
private symbolResolver: StaticSymbolResolver,
knownMetadataClasses: {name: string, filePath: string, ctor: any}[] = [],
knownMetadataFunctions: {name: string, filePath: string, fn: any}[] = [],
@ -47,6 +54,17 @@ export class StaticReflector implements ɵReflectorReader {
this.getStaticSymbol(kc.filePath, kc.name), kc.ctor));
knownMetadataFunctions.forEach(
(kf) => this._registerFunction(this.getStaticSymbol(kf.filePath, kf.name), kf.fn));
this.annotationForParentClassWithSummaryKind.set(
CompileSummaryKind.Directive, [Directive, Component]);
this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.Pipe, [Pipe]);
this.annotationForParentClassWithSummaryKind.set(CompileSummaryKind.NgModule, [NgModule]);
this.annotationForParentClassWithSummaryKind.set(
CompileSummaryKind.Injectable, [Injectable, Pipe, Directive, Component, NgModule]);
this.annotationNames.set(Directive, 'Directive');
this.annotationNames.set(Component, 'Component');
this.annotationNames.set(Pipe, 'Pipe');
this.annotationNames.set(NgModule, 'NgModule');
this.annotationNames.set(Injectable, 'Injectable');
}
importUri(typeOrFunc: StaticSymbol): string {
@ -96,17 +114,33 @@ export class StaticReflector implements ɵReflectorReader {
if (!annotations) {
annotations = [];
const classMetadata = this.getTypeMetadata(type);
if (classMetadata['extends']) {
const parentType = this.trySimplify(type, classMetadata['extends']);
if (parentType && (parentType instanceof StaticSymbol)) {
const parentAnnotations = this.annotations(parentType);
annotations.push(...parentAnnotations);
}
const parentType = this.findParentType(type, classMetadata);
if (parentType) {
const parentAnnotations = this.annotations(parentType);
annotations.push(...parentAnnotations);
}
let ownAnnotations: any[] = [];
if (classMetadata['decorators']) {
const ownAnnotations: any[] = this.simplify(type, classMetadata['decorators']);
ownAnnotations = this.simplify(type, classMetadata['decorators']);
annotations.push(...ownAnnotations);
}
if (parentType && !this.summaryResolver.isLibraryFile(type.filePath) &&
this.summaryResolver.isLibraryFile(parentType.filePath)) {
const summary = this.summaryResolver.resolveSummary(parentType);
if (summary && summary.type) {
const requiredAnnotationTypes =
this.annotationForParentClassWithSummaryKind.get(summary.type.summaryKind);
const typeHasRequiredAnnotation = requiredAnnotationTypes.some(
requiredType => ownAnnotations.some(ann => ann instanceof requiredType));
if (!typeHasRequiredAnnotation) {
this.reportError(
syntaxError(
`Class ${type.name} in ${type.filePath} extends from a ${CompileSummaryKind[summary.type.summaryKind]} in another compilation unit without duplicating the decorator. ` +
`Please add a ${requiredAnnotationTypes.map(type => this.annotationNames.get(type)).join(' or ')} decorator to the class.`),
type);
}
}
}
this.annotationCache.set(type, annotations.filter(ann => !!ann));
}
return annotations;
@ -117,14 +151,12 @@ export class StaticReflector implements ɵReflectorReader {
if (!propMetadata) {
const classMetadata = this.getTypeMetadata(type);
propMetadata = {};
if (classMetadata['extends']) {
const parentType = this.simplify(type, classMetadata['extends']);
if (parentType instanceof StaticSymbol) {
const parentPropMetadata = this.propMetadata(parentType);
Object.keys(parentPropMetadata).forEach((parentProp) => {
propMetadata[parentProp] = parentPropMetadata[parentProp];
});
}
const parentType = this.findParentType(type, classMetadata);
if (parentType) {
const parentPropMetadata = this.propMetadata(parentType);
Object.keys(parentPropMetadata).forEach((parentProp) => {
propMetadata[parentProp] = parentPropMetadata[parentProp];
});
}
const members = classMetadata['members'] || {};
@ -157,6 +189,7 @@ export class StaticReflector implements ɵReflectorReader {
let parameters = this.parameterCache.get(type);
if (!parameters) {
const classMetadata = this.getTypeMetadata(type);
const parentType = this.findParentType(type, classMetadata);
const members = classMetadata ? classMetadata['members'] : null;
const ctorData = members ? members['__ctor__'] : null;
if (ctorData) {
@ -175,11 +208,8 @@ export class StaticReflector implements ɵReflectorReader {
}
parameters.push(nestedResult);
});
} else if (classMetadata['extends']) {
const parentType = this.simplify(type, classMetadata['extends']);
if (parentType instanceof StaticSymbol) {
parameters = this.parameters(parentType);
}
} else if (parentType) {
parameters = this.parameters(parentType);
}
if (!parameters) {
parameters = [];
@ -198,14 +228,12 @@ export class StaticReflector implements ɵReflectorReader {
if (!methodNames) {
const classMetadata = this.getTypeMetadata(type);
methodNames = {};
if (classMetadata['extends']) {
const parentType = this.simplify(type, classMetadata['extends']);
if (parentType instanceof StaticSymbol) {
const parentMethodNames = this._methodNames(parentType);
Object.keys(parentMethodNames).forEach((parentProp) => {
methodNames[parentProp] = parentMethodNames[parentProp];
});
}
const parentType = this.findParentType(type, classMetadata);
if (parentType) {
const parentMethodNames = this._methodNames(parentType);
Object.keys(parentMethodNames).forEach((parentProp) => {
methodNames[parentProp] = parentMethodNames[parentProp];
});
}
const members = classMetadata['members'] || {};
@ -219,6 +247,13 @@ export class StaticReflector implements ɵReflectorReader {
return methodNames;
}
private findParentType(type: StaticSymbol, classMetadata: any): StaticSymbol|null {
const parentType = this.trySimplify(type, classMetadata['extends']);
if (parentType instanceof StaticSymbol) {
return parentType;
}
}
hasLifecycleHook(type: any, lcProperty: string): boolean {
if (!(type instanceof StaticSymbol)) {
this.reportError(
@ -549,7 +584,7 @@ export class StaticReflector implements ɵReflectorReader {
return simplifyCall(staticSymbol, targetFunction, argExpressions);
}
}
break;
return IGNORE;
case 'error':
let message = produceErrorMessage(expression);
if (expression['line']) {

View File

@ -59,6 +59,7 @@ export class StaticSymbolResolver {
// Note: this will only contain StaticSymbols without members!
private importAs = new Map<StaticSymbol, StaticSymbol>();
private symbolResourcePaths = new Map<StaticSymbol, string>();
private symbolFromFile = new Map<string, StaticSymbol[]>();
constructor(
private host: StaticSymbolResolverHost, private staticSymbolCache: StaticSymbolCache,
@ -143,6 +144,25 @@ export class StaticSymbolResolver {
this.importAs.set(sourceSymbol, targetSymbol);
}
/**
* Invalidate all information derived from the given file.
*
* @param fileName the file to invalidate
*/
invalidateFile(fileName: string) {
this.metadataCache.delete(fileName);
this.resolvedFilePaths.delete(fileName);
const symbols = this.symbolFromFile.get(fileName);
if (symbols) {
this.symbolFromFile.delete(fileName);
for (const symbol of symbols) {
this.resolvedSymbols.delete(symbol);
this.importAs.delete(symbol);
this.symbolResourcePaths.delete(symbol);
}
}
}
private _resolveSymbolMembers(staticSymbol: StaticSymbol): ResolvedStaticSymbol {
const members = staticSymbol.members;
const baseResolvedSymbol =
@ -281,11 +301,23 @@ export class StaticSymbolResolver {
}
resolvedSymbols.forEach(
(resolvedSymbol) => this.resolvedSymbols.set(resolvedSymbol.symbol, resolvedSymbol));
this.symbolFromFile.set(filePath, resolvedSymbols.map(resolvedSymbol => resolvedSymbol.symbol));
}
private createResolvedSymbol(
sourceSymbol: StaticSymbol, topLevelPath: string, topLevelSymbolNames: Set<string>,
metadata: any): ResolvedStaticSymbol {
// For classes that don't have Angular summaries / metadata,
// we only keep their arity, but nothing else
// (e.g. their constructor parameters).
// We do this to prevent introducing deep imports
// as we didn't generate .ngfactory.ts files with proper reexports.
if (this.summaryResolver.isLibraryFile(sourceSymbol.filePath) && metadata &&
metadata['__symbolic'] === 'class') {
const transformedMeta = {__symbolic: 'class', arity: metadata.arity};
return new ResolvedStaticSymbol(sourceSymbol, transformedMeta);
}
const self = this;
class ReferenceTransformer extends ValueTransformer {

View File

@ -53,7 +53,7 @@ export function serializeSummaries(
// (in a minimal way).
types.forEach((typeSummary) => {
serializer.addOrMergeSummary(
{symbol: typeSummary.type.reference, metadata: {__symbolic: 'class'}, type: typeSummary});
{symbol: typeSummary.type.reference, metadata: null, type: typeSummary});
if (typeSummary.summaryKind === CompileSummaryKind.NgModule) {
const ngModuleSummary = <CompileNgModuleSummary>typeSummary;
ngModuleSummary.exportedDirectives.concat(ngModuleSummary.exportedPipes).forEach((id) => {
@ -94,10 +94,21 @@ class Serializer extends ValueTransformer {
addOrMergeSummary(summary: Summary<StaticSymbol>) {
let symbolMeta = summary.metadata;
if (symbolMeta && symbolMeta.__symbolic === 'class') {
// For classes, we only keep their statics and arity, but not the metadata
// of the class itself as that has been captured already via other summaries
// (e.g. DirectiveSummary, ...).
symbolMeta = {__symbolic: 'class', statics: symbolMeta.statics, arity: symbolMeta.arity};
// For classes, we keep everything except their class decorators.
// We need to keep e.g. the ctor args, method names, method decorators
// so that the class can be extended in another compilation unit.
// We don't keep the class decorators as
// 1) they refer to data
// that should not cause a rebuild of downstream compilation units
// (e.g. inline templates of @Component, or @NgModule.declarations)
// 2) their data is already captured in TypeSummaries, e.g. DirectiveSummary.
const clone: {[key: string]: any} = {};
Object.keys(symbolMeta).forEach((propName) => {
if (propName !== 'decorators') {
clone[propName] = symbolMeta[propName];
}
});
symbolMeta = clone;
}
let processedSummary = this.processedSummaryBySymbol.get(summary.symbol);

View File

@ -388,7 +388,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
visitAll(asts: cdAst.AST[], mode: _Mode): any { return asts.map(ast => this.visit(ast, mode)); }
visitQuote(ast: cdAst.Quote, mode: _Mode): any {
throw new Error('Quotes are not supported for evaluation!');
throw new Error(`Quotes are not supported for evaluation!
Statement: ${ast.uninterpretedExpression} located at ${ast.location}`);
}
private visit(ast: cdAst.AST, mode: _Mode): any {

View File

@ -65,6 +65,10 @@ export class DirectiveNormalizer {
let normalizedTemplateSync: CompileTemplateMetadata = null;
let normalizedTemplateAsync: Promise<CompileTemplateMetadata>;
if (prenormData.template != null) {
if (prenormData.templateUrl != null) {
throw syntaxError(
`'${stringify(prenormData.componentType)}' component cannot define both template and templateUrl`);
}
if (typeof prenormData.template !== 'string') {
throw syntaxError(
`The template specified for component ${stringify(prenormData.componentType)} is not a string`);

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Directive, HostBinding, HostListener, Input, Output, Query, Type, resolveForwardRef, ɵReflectorReader, ɵmerge as merge, ɵreflector, ɵstringify as stringify} from '@angular/core';
import {Component, Directive, HostBinding, HostListener, Input, Output, Query, Type, resolveForwardRef, ɵReflectorReader, ɵreflector, ɵstringify as stringify} from '@angular/core';
import {CompilerInjectable} from './injectable';
import {splitAtColon} from './util';
@ -124,8 +124,8 @@ export class DirectiveResolver {
this._dedupeBindings(directive.inputs ? directive.inputs.concat(inputs) : inputs);
const mergedOutputs =
this._dedupeBindings(directive.outputs ? directive.outputs.concat(outputs) : outputs);
const mergedHost = directive.host ? merge(directive.host, host) : host;
const mergedQueries = directive.queries ? merge(directive.queries, queries) : queries;
const mergedHost = directive.host ? {...directive.host, ...host} : host;
const mergedQueries = directive.queries ? {...directive.queries, ...queries} : queries;
if (directive instanceof Component) {
return new Component({

View File

@ -94,7 +94,7 @@ export class Extractor {
const symbolCache = new StaticSymbolCache();
const summaryResolver = new AotSummaryResolver(host, symbolCache);
const staticSymbolResolver = new StaticSymbolResolver(host, symbolCache, summaryResolver);
const staticReflector = new StaticReflector(staticSymbolResolver);
const staticReflector = new StaticReflector(summaryResolver, staticSymbolResolver);
StaticAndDynamicReflectionCapabilities.install(staticReflector);
const config =

View File

@ -13,6 +13,7 @@ import {ParseTreeResult} from '../ml_parser/parser';
import {mergeTranslations} from './extractor_merger';
import {Serializer} from './serializers/serializer';
import {Xliff} from './serializers/xliff';
import {Xliff2} from './serializers/xliff2';
import {Xmb} from './serializers/xmb';
import {Xtb} from './serializers/xtb';
import {TranslationBundle} from './translation_bundle';
@ -62,6 +63,9 @@ function createSerializer(format?: string): Serializer {
return new Xmb();
case 'xtb':
return new Xtb();
case 'xliff2':
case 'xlf2':
return new Xliff2();
case 'xliff':
case 'xlf':
default:

View File

@ -161,8 +161,9 @@ class _I18nVisitor implements html.Visitor {
}
}
const _CUSTOM_PH_EXP = /\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*"([\s\S]*?)"[\s\S]*\)/g;
const _CUSTOM_PH_EXP =
/\/\/[\s\S]*i18n[\s\S]*\([\s\S]*ph[\s\S]*=[\s\S]*("|')([\s\S]*?)\1[\s\S]*\)/g;
function _extractPlaceholderName(input: string): string {
return input.split(_CUSTOM_PH_EXP)[1];
return input.split(_CUSTOM_PH_EXP)[2];
}

View File

@ -11,5 +11,6 @@ export {I18NHtmlParser} from './i18n_html_parser';
export {MessageBundle} from './message_bundle';
export {Serializer} from './serializers/serializer';
export {Xliff} from './serializers/xliff';
export {Xliff2} from './serializers/xliff2';
export {Xmb} from './serializers/xmb';
export {Xtb} from './serializers/xtb';

View File

@ -0,0 +1,370 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ml from '../../ml_parser/ast';
import {XmlParser} from '../../ml_parser/xml_parser';
import {decimalDigest} from '../digest';
import * as i18n from '../i18n_ast';
import {I18nError} from '../parse_util';
import {Serializer} from './serializer';
import * as xml from './xml_helper';
const _VERSION = '2.0';
const _XMLNS = 'urn:oasis:names:tc:xliff:document:2.0';
// TODO(vicb): make this a param (s/_/-/)
const _DEFAULT_SOURCE_LANG = 'en';
const _PLACEHOLDER_TAG = 'ph';
const _PLACEHOLDER_SPANNING_TAG = 'pc';
const _XLIFF_TAG = 'xliff';
const _SOURCE_TAG = 'source';
const _TARGET_TAG = 'target';
const _UNIT_TAG = 'unit';
// http://docs.oasis-open.org/xliff/xliff-core/v2.0/os/xliff-core-v2.0-os.html
export class Xliff2 extends Serializer {
write(messages: i18n.Message[], locale: string|null): string {
const visitor = new _WriteVisitor();
const units: xml.Node[] = [];
messages.forEach(message => {
const unit = new xml.Tag(_UNIT_TAG, {id: message.id});
if (message.description || message.meaning) {
const notes = new xml.Tag('notes');
if (message.description) {
notes.children.push(
new xml.CR(8),
new xml.Tag('note', {category: 'description'}, [new xml.Text(message.description)]));
}
if (message.meaning) {
notes.children.push(
new xml.CR(8),
new xml.Tag('note', {category: 'meaning'}, [new xml.Text(message.meaning)]));
}
notes.children.push(new xml.CR(6));
unit.children.push(new xml.CR(6), notes);
}
const segment = new xml.Tag('segment');
segment.children.push(
new xml.CR(8), new xml.Tag(_SOURCE_TAG, {}, visitor.serialize(message.nodes)),
new xml.CR(6));
unit.children.push(new xml.CR(6), segment, new xml.CR(4));
units.push(new xml.CR(4), unit);
});
const file =
new xml.Tag('file', {'original': 'ng.template', id: 'ngi18n'}, [...units, new xml.CR(2)]);
const xliff = new xml.Tag(
_XLIFF_TAG, {version: _VERSION, xmlns: _XMLNS, srcLang: locale || _DEFAULT_SOURCE_LANG},
[new xml.CR(2), file, new xml.CR()]);
return xml.serialize([
new xml.Declaration({version: '1.0', encoding: 'UTF-8'}), new xml.CR(), xliff, new xml.CR()
]);
}
load(content: string, url: string):
{locale: string, i18nNodesByMsgId: {[msgId: string]: i18n.Node[]}} {
// xliff to xml nodes
const xliff2Parser = new Xliff2Parser();
const {locale, msgIdToHtml, errors} = xliff2Parser.parse(content, url);
// xml nodes to i18n nodes
const i18nNodesByMsgId: {[msgId: string]: i18n.Node[]} = {};
const converter = new XmlToI18n();
Object.keys(msgIdToHtml).forEach(msgId => {
const {i18nNodes, errors: e} = converter.convert(msgIdToHtml[msgId], url);
errors.push(...e);
i18nNodesByMsgId[msgId] = i18nNodes;
});
if (errors.length) {
throw new Error(`xliff2 parse errors:\n${errors.join('\n')}`);
}
return {locale: locale !, i18nNodesByMsgId};
}
digest(message: i18n.Message): string { return decimalDigest(message); }
}
class _WriteVisitor implements i18n.Visitor {
private _nextPlaceholderId: number;
visitText(text: i18n.Text, context?: any): xml.Node[] { return [new xml.Text(text.value)]; }
visitContainer(container: i18n.Container, context?: any): xml.Node[] {
const nodes: xml.Node[] = [];
container.children.forEach((node: i18n.Node) => nodes.push(...node.visit(this)));
return nodes;
}
visitIcu(icu: i18n.Icu, context?: any): xml.Node[] {
const nodes = [new xml.Text(`{${icu.expressionPlaceholder}, ${icu.type}, `)];
Object.keys(icu.cases).forEach((c: string) => {
nodes.push(new xml.Text(`${c} {`), ...icu.cases[c].visit(this), new xml.Text(`} `));
});
nodes.push(new xml.Text(`}`));
return nodes;
}
visitTagPlaceholder(ph: i18n.TagPlaceholder, context?: any): xml.Node[] {
const type = getTypeForTag(ph.tag);
if (ph.isVoid) {
const tagPh = new xml.Tag(_PLACEHOLDER_TAG, {
id: (this._nextPlaceholderId++).toString(),
equiv: ph.startName,
type: type,
disp: `<${ph.tag}/>`,
});
return [tagPh];
}
const tagPc = new xml.Tag(_PLACEHOLDER_SPANNING_TAG, {
id: (this._nextPlaceholderId++).toString(),
equivStart: ph.startName,
equivEnd: ph.closeName,
type: type,
dispStart: `<${ph.tag}>`,
dispEnd: `</${ph.tag}>`,
});
const nodes: xml.Node[] = [].concat(...ph.children.map(node => node.visit(this)));
if (nodes.length) {
nodes.forEach((node: xml.Node) => tagPc.children.push(node));
} else {
tagPc.children.push(new xml.Text(''));
}
return [tagPc];
}
visitPlaceholder(ph: i18n.Placeholder, context?: any): xml.Node[] {
return [new xml.Tag(_PLACEHOLDER_TAG, {
id: (this._nextPlaceholderId++).toString(),
equiv: ph.name,
disp: `{{${ph.value}}}`,
})];
}
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): xml.Node[] {
return [new xml.Tag(_PLACEHOLDER_TAG, {id: (this._nextPlaceholderId++).toString()})];
}
serialize(nodes: i18n.Node[]): xml.Node[] {
this._nextPlaceholderId = 0;
return [].concat(...nodes.map(node => node.visit(this)));
}
}
// Extract messages as xml nodes from the xliff file
class Xliff2Parser implements ml.Visitor {
private _unitMlString: string|null;
private _errors: I18nError[];
private _msgIdToHtml: {[msgId: string]: string};
private _locale: string|null = null;
parse(xliff: string, url: string) {
this._unitMlString = null;
this._msgIdToHtml = {};
const xml = new XmlParser().parse(xliff, url, false);
this._errors = xml.errors;
ml.visitAll(this, xml.rootNodes, null);
return {
msgIdToHtml: this._msgIdToHtml,
errors: this._errors,
locale: this._locale,
};
}
visitElement(element: ml.Element, context: any): any {
switch (element.name) {
case _UNIT_TAG:
this._unitMlString = null;
const idAttr = element.attrs.find((attr) => attr.name === 'id');
if (!idAttr) {
this._addError(element, `<${_UNIT_TAG}> misses the "id" attribute`);
} else {
const id = idAttr.value;
if (this._msgIdToHtml.hasOwnProperty(id)) {
this._addError(element, `Duplicated translations for msg ${id}`);
} else {
ml.visitAll(this, element.children, null);
if (typeof this._unitMlString === 'string') {
this._msgIdToHtml[id] = this._unitMlString;
} else {
this._addError(element, `Message ${id} misses a translation`);
}
}
}
break;
case _SOURCE_TAG:
// ignore source message
break;
case _TARGET_TAG:
const innerTextStart = element.startSourceSpan !.end.offset;
const innerTextEnd = element.endSourceSpan !.start.offset;
const content = element.startSourceSpan !.start.file.content;
const innerText = content.slice(innerTextStart, innerTextEnd);
this._unitMlString = innerText;
break;
case _XLIFF_TAG:
const localeAttr = element.attrs.find((attr) => attr.name === 'trgLang');
if (localeAttr) {
this._locale = localeAttr.value;
}
const versionAttr = element.attrs.find((attr) => attr.name === 'version');
if (versionAttr) {
const version = versionAttr.value;
if (version !== '2.0') {
this._addError(
element,
`The XLIFF file version ${version} is not compatible with XLIFF 2.0 serializer`);
} else {
ml.visitAll(this, element.children, null);
}
}
break;
default:
ml.visitAll(this, element.children, null);
}
}
visitAttribute(attribute: ml.Attribute, context: any): any {}
visitText(text: ml.Text, context: any): any {}
visitComment(comment: ml.Comment, context: any): any {}
visitExpansion(expansion: ml.Expansion, context: any): any {}
visitExpansionCase(expansionCase: ml.ExpansionCase, context: any): any {}
private _addError(node: ml.Node, message: string): void {
this._errors.push(new I18nError(node.sourceSpan, message));
}
}
// Convert ml nodes (xliff syntax) to i18n nodes
class XmlToI18n implements ml.Visitor {
private _errors: I18nError[];
convert(message: string, url: string) {
const xmlIcu = new XmlParser().parse(message, url, true);
this._errors = xmlIcu.errors;
const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ?
[] :
[].concat(...ml.visitAll(this, xmlIcu.rootNodes));
return {
i18nNodes,
errors: this._errors,
};
}
visitText(text: ml.Text, context: any) { return new i18n.Text(text.value, text.sourceSpan); }
visitElement(el: ml.Element, context: any): i18n.Node[]|null {
switch (el.name) {
case _PLACEHOLDER_TAG:
const nameAttr = el.attrs.find((attr) => attr.name === 'equiv');
if (nameAttr) {
return [new i18n.Placeholder('', nameAttr.value, el.sourceSpan)];
}
this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "equiv" attribute`);
break;
case _PLACEHOLDER_SPANNING_TAG:
const startAttr = el.attrs.find((attr) => attr.name === 'equivStart');
const endAttr = el.attrs.find((attr) => attr.name === 'equivEnd');
if (!startAttr) {
this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "equivStart" attribute`);
} else if (!endAttr) {
this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "equivEnd" attribute`);
} else {
const startId = startAttr.value;
const endId = endAttr.value;
const nodes: i18n.Node[] = [];
return nodes.concat(
new i18n.Placeholder('', startId, el.sourceSpan),
...el.children.map(node => node.visit(this, null)),
new i18n.Placeholder('', endId, el.sourceSpan));
}
break;
default:
this._addError(el, `Unexpected tag`);
}
return null;
}
visitExpansion(icu: ml.Expansion, context: any) {
const caseMap: {[value: string]: i18n.Node} = {};
ml.visitAll(this, icu.cases).forEach((c: any) => {
caseMap[c.value] = new i18n.Container(c.nodes, icu.sourceSpan);
});
return new i18n.Icu(icu.switchValue, icu.type, caseMap, icu.sourceSpan);
}
visitExpansionCase(icuCase: ml.ExpansionCase, context: any): any {
return {
value: icuCase.value,
nodes: [].concat(...ml.visitAll(this, icuCase.expression)),
};
}
visitComment(comment: ml.Comment, context: any) {}
visitAttribute(attribute: ml.Attribute, context: any) {}
private _addError(node: ml.Node, message: string): void {
this._errors.push(new I18nError(node.sourceSpan, message));
}
}
function getTypeForTag(tag: string): string {
switch (tag.toLowerCase()) {
case 'br':
case 'b':
case 'i':
case 'u':
return 'fmt';
case 'img':
return 'image';
case 'a':
return 'link';
default:
return 'other';
}
}

View File

@ -529,6 +529,7 @@ export class CompileMetadataResolver {
syntaxError(
`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${stringifyType(exportedId.reference)} from ${stringifyType(moduleType)} as it was neither declared nor imported!`),
moduleType);
return;
}
});
@ -627,6 +628,7 @@ export class CompileMetadataResolver {
`Please consider moving ${stringifyType(type)} to a higher module that imports ${stringifyType(oldModule)} and ${stringifyType(moduleType)}. ` +
`You can also create a new NgModule that exports and includes ${stringifyType(type)} then import that NgModule in ${stringifyType(oldModule)} and ${stringifyType(moduleType)}.`),
moduleType);
return;
}
this._ngModuleOfTypes.set(type, moduleType);
}
@ -860,6 +862,7 @@ export class CompileMetadataResolver {
} else if (provider === void 0) {
this._reportError(syntaxError(
`Encountered undefined provider! Usually this means you have a circular dependencies (might be caused by using 'barrel' index.ts files.`));
return;
} else {
const providersInfo =
(<string[]>providers.reduce(
@ -879,6 +882,7 @@ export class CompileMetadataResolver {
syntaxError(
`Invalid ${debugInfo ? debugInfo : 'provider'} - only instances of Provider and Type are allowed, got: [${providersInfo}]`),
type);
return;
}
if (providerMeta.token === resolveIdentifier(Identifiers.ANALYZE_FOR_ENTRY_COMPONENTS)) {
targetEntryComponents.push(...this._getEntryComponentsFromProvider(providerMeta, type));
@ -933,14 +937,12 @@ export class CompileMetadataResolver {
const dirMeta = this.getNonNormalizedDirectiveMetadata(dirType);
if (dirMeta && dirMeta.metadata.isComponent) {
return {componentType: dirType, componentFactory: dirMeta.metadata.componentFactory};
} else {
const dirSummary =
<cpl.CompileDirectiveSummary>this._loadSummary(dirType, cpl.CompileSummaryKind.Directive);
if (dirSummary && dirSummary.isComponent) {
return {componentType: dirType, componentFactory: dirSummary.componentFactory};
}
}
const dirSummary =
<cpl.CompileDirectiveSummary>this._loadSummary(dirType, cpl.CompileSummaryKind.Directive);
if (dirSummary && dirSummary.isComponent) {
return {componentType: dirType, componentFactory: dirSummary.componentFactory};
}
if (throwIfNotFound) {
throw syntaxError(`${dirType.name} cannot be used as an entry component.`);
}
@ -1004,8 +1006,10 @@ export class CompileMetadataResolver {
syntaxError(
`Can't construct a query for the property "${propertyName}" of "${stringifyType(typeOrFunc)}" since the query selector wasn't defined.`),
typeOrFunc);
selectors = [];
} else {
selectors = [this._getTokenMetadata(q.selector)];
}
selectors = [this._getTokenMetadata(q.selector)];
}
return {

View File

@ -140,13 +140,13 @@ export class TemplateParser {
return this.tryParseHtml(
this.expandHtml(this._htmlParser.parse(
template, templateUrl, true, this.getInterpolationConfig(component))),
component, template, directives, pipes, schemas, templateUrl);
component, directives, pipes, schemas);
}
tryParseHtml(
htmlAstWithErrors: ParseTreeResult, component: CompileDirectiveMetadata, template: string,
directives: CompileDirectiveSummary[], pipes: CompilePipeSummary[], schemas: SchemaMetadata[],
templateUrl: string): TemplateParseResult {
htmlAstWithErrors: ParseTreeResult, component: CompileDirectiveMetadata,
directives: CompileDirectiveSummary[], pipes: CompilePipeSummary[],
schemas: SchemaMetadata[]): TemplateParseResult {
let result: TemplateAst[];
const errors = htmlAstWithErrors.errors;
const usedPipes: CompilePipeSummary[] = [];

View File

@ -644,8 +644,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
return EventHandlerVars.event;
}
let currViewExpr: o.Expression = VIEW_VAR;
for (let currBuilder: ViewBuilder = this; currBuilder;
currBuilder = currBuilder.parent, currViewExpr = currViewExpr.prop('parent')) {
for (let currBuilder: ViewBuilder = this; currBuilder; currBuilder = currBuilder.parent,
currViewExpr = currViewExpr.prop('parent').cast(o.DYNAMIC_TYPE)) {
// check references
const refNodeIndex = currBuilder.refNodeIndices[name];
if (refNodeIndex != null) {
@ -717,7 +717,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
let compBuilder: ViewBuilder = this;
while (compBuilder.parent) {
compBuilder = compBuilder.parent;
compViewExpr = compViewExpr.prop('parent');
compViewExpr = compViewExpr.prop('parent').cast(o.DYNAMIC_TYPE);
}
const pipeNodeIndex = compBuilder.purePipeNodeIndices[name];
const pipeValueExpr: o.Expression =

View File

@ -8,6 +8,7 @@
import {AotCompiler, AotCompilerHost, AotCompilerOptions, GeneratedFile, createAotCompiler} from '@angular/compiler';
import {RenderComponentType, ɵReflectionCapabilities as ReflectionCapabilities, ɵreflector as reflector} from '@angular/core';
import {NodeFlags} from '@angular/core/src/view/index';
import {async} from '@angular/core/testing';
import {MetadataBundler, MetadataCollector, ModuleMetadata, privateEntriesToIndex} from '@angular/tsc-wrapped';
import * as ts from 'typescript';
@ -368,6 +369,293 @@ describe('compiler (unbundled Angular)', () => {
}));
});
describe('inheritance with summaries', () => {
function compileWithSummaries(
libInput: MockData, appInput: MockData): Promise<GeneratedFile[]> {
const libHost = new MockCompilerHost(['/lib/base.ts'], libInput, angularFiles);
const libAotHost = new MockAotCompilerHost(libHost);
libAotHost.tsFilesOnly();
const appHost = new MockCompilerHost(['/app/main.ts'], appInput, angularFiles);
const appAotHost = new MockAotCompilerHost(appHost);
appAotHost.tsFilesOnly();
return compile(libHost, libAotHost, expectNoDiagnostics, expectNoDiagnosticsAndEmit)
.then(() => {
libHost.writtenFiles.forEach((value, key) => appHost.writeFile(key, value, false));
libHost.overrides.forEach((value, key) => appHost.override(key, value));
return compile(appHost, appAotHost, expectNoDiagnostics, expectNoDiagnosticsAndEmit);
});
}
function compileParentAndChild(
{parentClassDecorator, parentModuleDecorator, childClassDecorator, childModuleDecorator}: {
parentClassDecorator: string,
parentModuleDecorator: string,
childClassDecorator: string,
childModuleDecorator: string
}) {
const libInput: MockData = {
'lib': {
'base.ts': `
import {Injectable, Pipe, Directive, Component, NgModule} from '@angular/core';
${parentClassDecorator}
export class Base {}
${parentModuleDecorator}
export class BaseModule {}
`
}
};
const appInput: MockData = {
'app': {
'main.ts': `
import {Injectable, Pipe, Directive, Component, NgModule} from '@angular/core';
import {Base} from '../lib/base';
${childClassDecorator}
export class Extends extends Base {}
${childModuleDecorator}
export class MyModule {}
`
}
};
return compileWithSummaries(libInput, appInput)
.then((generatedFiles) => generatedFiles.find(gf => gf.srcFileUrl === '/app/main.ts'));
}
it('should inherit ctor and lifecycle hooks from classes in other compilation units',
async(() => {
const libInput: MockData = {
'lib': {
'base.ts': `
export class AParam {}
export class Base {
constructor(a: AParam) {}
ngOnDestroy() {}
}
`
}
};
const appInput: MockData = {
'app': {
'main.ts': `
import {NgModule, Component} from '@angular/core';
import {Base} from '../lib/base';
@Component({template: ''})
export class Extends extends Base {}
@NgModule({
declarations: [Extends]
})
export class MyModule {}
`
}
};
compileWithSummaries(libInput, appInput).then((generatedFiles) => {
const mainNgFactory = generatedFiles.find(gf => gf.srcFileUrl === '/app/main.ts');
const flags = NodeFlags.TypeDirective | NodeFlags.Component | NodeFlags.OnDestroy;
expect(mainNgFactory.source)
.toContain(`${flags},(null as any),0,import1.Extends,[import2.AParam]`);
});
}));
it('should inherit ctor and lifecycle hooks from classes in other compilation units over 2 levels',
async(() => {
const lib1Input: MockData = {
'lib1': {
'base.ts': `
export class AParam {}
export class Base {
constructor(a: AParam) {}
ngOnDestroy() {}
}
`
}
};
const lib2Input: MockData = {
'lib2': {
'middle.ts': `
import {Base} from '../lib1/base';
export class Middle extends Base {}
`
}
};
const appInput: MockData = {
'app': {
'main.ts': `
import {NgModule, Component} from '@angular/core';
import {Middle} from '../lib2/middle';
@Component({template: ''})
export class Extends extends Middle {}
@NgModule({
declarations: [Extends]
})
export class MyModule {}
`
}
};
const lib1Host = new MockCompilerHost(['/lib1/base.ts'], lib1Input, angularFiles);
const lib1AotHost = new MockAotCompilerHost(lib1Host);
lib1AotHost.tsFilesOnly();
const lib2Host = new MockCompilerHost(['/lib2/middle.ts'], lib2Input, angularFiles);
const lib2AotHost = new MockAotCompilerHost(lib2Host);
lib2AotHost.tsFilesOnly();
const appHost = new MockCompilerHost(['/app/main.ts'], appInput, angularFiles);
const appAotHost = new MockAotCompilerHost(appHost);
appAotHost.tsFilesOnly();
compile(lib1Host, lib1AotHost, expectNoDiagnostics, expectNoDiagnosticsAndEmit)
.then(() => {
lib1Host.writtenFiles.forEach((value, key) => lib2Host.writeFile(key, value, false));
lib1Host.overrides.forEach((value, key) => lib2Host.override(key, value));
return compile(
lib2Host, lib2AotHost, expectNoDiagnostics, expectNoDiagnosticsAndEmit);
})
.then(() => {
lib2Host.writtenFiles.forEach((value, key) => appHost.writeFile(key, value, false));
lib2Host.overrides.forEach((value, key) => appHost.override(key, value));
return compile(appHost, appAotHost, expectNoDiagnostics, expectNoDiagnosticsAndEmit);
})
.then((generatedFiles) => {
const mainNgFactory = generatedFiles.find(gf => gf.srcFileUrl === '/app/main.ts');
const flags = NodeFlags.TypeDirective | NodeFlags.Component | NodeFlags.OnDestroy;
expect(mainNgFactory.source)
.toContain(`${flags},(null as any),0,import1.Extends,[import2.AParam_2]`);
});
}));
describe('Injectable', () => {
it('should allow to inherit', async(() => {
compileParentAndChild({
parentClassDecorator: '@Injectable()',
parentModuleDecorator: '@NgModule({providers: [Base]})',
childClassDecorator: '@Injectable()',
childModuleDecorator: '@NgModule({providers: [Extends]})',
}).then((mainNgFactory) => { expect(mainNgFactory).toBeTruthy(); });
}));
it('should error if the child class has no matching decorator', async(() => {
compileParentAndChild({
parentClassDecorator: '@Injectable()',
parentModuleDecorator: '@NgModule({providers: [Base]})',
childClassDecorator: '',
childModuleDecorator: '@NgModule({providers: [Extends]})',
}).then(fail, (e) => {
expect(e.message).toContain(
'Class Extends in /app/main.ts extends from a Injectable in another compilation unit without duplicating the decorator. ' +
'Please add a Injectable or Pipe or Directive or Component or NgModule decorator to the class.');
});
}));
});
describe('Component', () => {
it('should allow to inherit', async(() => {
compileParentAndChild({
parentClassDecorator: `@Component({template: ''})`,
parentModuleDecorator: '@NgModule({declarations: [Base]})',
childClassDecorator: `@Component({template: ''})`,
childModuleDecorator: '@NgModule({declarations: [Extends]})',
}).then((mainNgFactory) => { expect(mainNgFactory).toBeTruthy(); });
}));
it('should error if the child class has no matching decorator', async(() => {
compileParentAndChild({
parentClassDecorator: `@Component({template: ''})`,
parentModuleDecorator: '@NgModule({declarations: [Base]})',
childClassDecorator: '',
childModuleDecorator: '@NgModule({declarations: [Extends]})',
}).then(fail, (e) => {
expect(e.message).toContain(
'Class Extends in /app/main.ts extends from a Directive in another compilation unit without duplicating the decorator. ' +
'Please add a Directive or Component decorator to the class.');
});
}));
});
describe('Directive', () => {
it('should allow to inherit', async(() => {
compileParentAndChild({
parentClassDecorator: `@Directive({selector: '[someDir]'})`,
parentModuleDecorator: '@NgModule({declarations: [Base]})',
childClassDecorator: `@Directive({selector: '[someDir]'})`,
childModuleDecorator: '@NgModule({declarations: [Extends]})',
}).then((mainNgFactory) => { expect(mainNgFactory).toBeTruthy(); });
}));
it('should error if the child class has no matching decorator', async(() => {
compileParentAndChild({
parentClassDecorator: `@Directive({selector: '[someDir]'})`,
parentModuleDecorator: '@NgModule({declarations: [Base]})',
childClassDecorator: '',
childModuleDecorator: '@NgModule({declarations: [Extends]})',
}).then(fail, (e) => {
expect(e.message).toContain(
'Class Extends in /app/main.ts extends from a Directive in another compilation unit without duplicating the decorator. ' +
'Please add a Directive or Component decorator to the class.');
});
}));
});
describe('Pipe', () => {
it('should allow to inherit', async(() => {
compileParentAndChild({
parentClassDecorator: `@Pipe({name: 'somePipe'})`,
parentModuleDecorator: '@NgModule({declarations: [Base]})',
childClassDecorator: `@Pipe({name: 'somePipe'})`,
childModuleDecorator: '@NgModule({declarations: [Extends]})',
}).then((mainNgFactory) => { expect(mainNgFactory).toBeTruthy(); });
}));
it('should error if the child class has no matching decorator', async(() => {
compileParentAndChild({
parentClassDecorator: `@Pipe({name: 'somePipe'})`,
parentModuleDecorator: '@NgModule({declarations: [Base]})',
childClassDecorator: '',
childModuleDecorator: '@NgModule({declarations: [Extends]})',
}).then(fail, (e) => {
expect(e.message).toContain(
'Class Extends in /app/main.ts extends from a Pipe in another compilation unit without duplicating the decorator. ' +
'Please add a Pipe decorator to the class.');
});
}));
});
describe('NgModule', () => {
it('should allow to inherit', async(() => {
compileParentAndChild({
parentClassDecorator: `@NgModule()`,
parentModuleDecorator: '',
childClassDecorator: `@NgModule()`,
childModuleDecorator: '',
}).then((mainNgFactory) => { expect(mainNgFactory).toBeTruthy(); });
}));
it('should error if the child class has no matching decorator', async(() => {
compileParentAndChild({
parentClassDecorator: `@NgModule()`,
parentModuleDecorator: '',
childClassDecorator: '',
childModuleDecorator: '',
}).then(fail, (e) => {
expect(e.message).toContain(
'Class Extends in /app/main.ts extends from a NgModule in another compilation unit without duplicating the decorator. ' +
'Please add a NgModule decorator to the class.');
});
}));
});
});
});
describe('compiler (bundled Angular)', () => {
@ -513,6 +801,11 @@ function expectNoDiagnostics(program: ts.Program) {
expectNoDiagnostics(program.getSemanticDiagnostics());
}
function expectNoDiagnosticsAndEmit(program: ts.Program) {
expectNoDiagnostics(program);
program.emit();
}
function isDTS(fileName: string): boolean {
return /\.d\.ts$/.test(fileName);
}
@ -544,7 +837,7 @@ function summaryCompile(
function compile(
host: MockCompilerHost, aotHost: AotCompilerHost, preCompile?: (program: ts.Program) => void,
postCompile: (program: ts.Program) => void = expectNoDiagnostics,
options: AotCompilerOptions = {}) {
options: AotCompilerOptions = {}): Promise<GeneratedFile[]> {
const scripts = host.scriptNames.slice(0);
const program = ts.createProgram(scripts, settings, host);
if (preCompile) preCompile(program);

View File

@ -24,9 +24,10 @@ describe('StaticReflector', () => {
errorRecorder?: (error: any, fileName: string) => void, collectorOptions?: CollectorOptions) {
const symbolCache = new StaticSymbolCache();
host = new MockStaticSymbolResolverHost(testData, collectorOptions);
symbolResolver =
new StaticSymbolResolver(host, symbolCache, new MockSummaryResolver([]), errorRecorder);
reflector = new StaticReflector(symbolResolver, decorators, [], errorRecorder);
const summaryResolver = new MockSummaryResolver([]);
spyOn(summaryResolver, 'isLibraryFile').and.returnValue(false);
symbolResolver = new StaticSymbolResolver(host, symbolCache, summaryResolver, errorRecorder);
reflector = new StaticReflector(summaryResolver, symbolResolver, decorators, [], errorRecorder);
noContext = reflector.getStaticSymbol('', '');
}
@ -495,6 +496,31 @@ describe('StaticReflector', () => {
expect(() => reflector.propMetadata(appComponent)).not.toThrow();
});
it('should not throw with an invalid extends', () => {
const data = Object.create(DEFAULT_TEST_DATA);
const file = '/tmp/src/invalid-component.ts';
data[file] = `
import {Component} from '@angular/core';
function InvalidParent() {
return InvalidParent;
}
@Component({
selector: 'tmp',
template: '',
})
export class BadComponent extends InvalidParent() {
}
`;
init(data);
const badComponent = reflector.getStaticSymbol(file, 'BadComponent');
expect(reflector.propMetadata(badComponent)).toEqual({});
expect(reflector.parameters(badComponent)).toEqual([]);
expect(reflector.hasLifecycleHook(badComponent, 'onDestroy')).toEqual(false);
});
it('should produce a annotation even if it contains errors', () => {
const data = Object.create(DEFAULT_TEST_DATA);
const file = '/tmp/src/invalid-component.ts';
@ -520,6 +546,30 @@ describe('StaticReflector', () => {
expect(annotation.providers).toEqual([1, 2, 3, 4, 5, 6, 7]);
});
it('should ignore unresolved calls', () => {
const data = Object.create(DEFAULT_TEST_DATA);
const file = '/tmp/src/invalid-component.ts';
data[file] = `
import {Component} from '@angular/core';
import {unknown} from 'unresolved';
@Component({
selector: 'tmp',
template: () => {},
providers: [triggers()]
})
export class BadComponent {
}
`;
init(data, [], () => {}, {verboseInvalidExpression: true});
const badComponent = reflector.getStaticSymbol(file, 'BadComponent');
const annotations = reflector.annotations(badComponent);
const annotation = annotations[0];
expect(annotation.providers).toEqual([]);
});
describe('inheritance', () => {
class ClassDecorator {
constructor(public value: any) {}

View File

@ -283,6 +283,31 @@ describe('StaticSymbolResolver', () => {
]);
});
it('should only use the arity for classes from libraries without summaries', () => {
init({
'/test.d.ts': [{
'__symbolic': 'module',
'version': 3,
'metadata': {
'AParam': {__symbolic: 'class'},
'AClass': {
__symbolic: 'class',
arity: 1,
members: {
__ctor__: [{
__symbolic: 'constructor',
parameters: [symbolCache.get('/test.d.ts', 'AParam')]
}]
}
}
}
}]
});
expect(symbolResolver.resolveSymbol(symbolCache.get('/test.d.ts', 'AClass')).metadata)
.toEqual({__symbolic: 'class', arity: 1});
});
it('should be able to trace a named export', () => {
const symbol = symbolResolver
.resolveSymbol(symbolResolver.getSymbolByModule(
@ -411,6 +436,9 @@ export class MockStaticSymbolResolverHost implements StaticSymbolResolverHost {
}
return baseName + '.d.ts';
}
if (modulePath == 'unresolved') {
return undefined;
}
return '/tmp/' + modulePath + '.d.ts';
}

View File

@ -61,7 +61,8 @@ export function main() {
metadata: {
__symbolic: 'class',
members: {'aMethod': {__symbolic: 'function'}},
statics: {aStatic: true}
statics: {aStatic: true},
decorators: ['aDecoratorData']
}
}
],
@ -88,8 +89,12 @@ export function main() {
});
expect(summaries[1].symbol).toBe(symbolCache.get('/tmp/some_service.d.ts', 'SomeService'));
// serialization should only keep the statics...
expect(summaries[1].metadata).toEqual({__symbolic: 'class', statics: {aStatic: true}});
// serialization should drop class decorators
expect(summaries[1].metadata).toEqual({
__symbolic: 'class',
members: {aMethod: {__symbolic: 'function'}},
statics: {aStatic: true}
});
expect(summaries[1].type.type.reference)
.toBe(symbolCache.get('/tmp/some_service.d.ts', 'SomeService'));
});

View File

@ -177,8 +177,8 @@ export class MockCompilerHost implements ts.CompilerHost {
private angularSourcePath: string|undefined;
private nodeModulesPath: string|undefined;
private overrides = new Map<string, string>();
private writtenFiles = new Map<string, string>();
public overrides = new Map<string, string>();
public writtenFiles = new Map<string, string>();
private sourceFiles = new Map<string, ts.SourceFile>();
private assumeExists = new Set<string>();
private traces: string[] = [];

View File

@ -51,6 +51,16 @@ export function main() {
templateUrl: <any>{}
})).toThrowError('The templateUrl specified for component SomeComp is not a string');
}));
it('should throw if both template and templateUrl are defined',
inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => {
expect(() => normalizer.normalizeTemplate({
ngModuleType: null,
componentType: SomeComp,
moduleUrl: SOME_MODULE_URL,
template: '',
templateUrl: '',
})).toThrowError(`'SomeComp' component cannot define both template and templateUrl`);
}));
});
describe('normalizeTemplateSync', () => {

View File

@ -125,6 +125,12 @@ export function main() {
.toEqual([
[['[before, <ph name="TEST"> exp //i18n(ph="teSt") </ph>, after]'], 'm', 'd'],
]);
expect(
_humanizeMessages('<div i18n=\'m|d\'>before{{ exp //i18n(ph=\'teSt\') }}after</div>'))
.toEqual([
[[`[before, <ph name="TEST"> exp //i18n(ph='teSt') </ph>, after]`], 'm', 'd'],
]);
});
});

View File

@ -0,0 +1,336 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {escapeRegExp} from '@angular/compiler/src/util';
import {serializeNodes} from '../../../src/i18n/digest';
import {MessageBundle} from '../../../src/i18n/message_bundle';
import {Xliff2} from '../../../src/i18n/serializers/xliff2';
import {HtmlParser} from '../../../src/ml_parser/html_parser';
import {DEFAULT_INTERPOLATION_CONFIG} from '../../../src/ml_parser/interpolation_config';
const HTML = `
<p i18n-title title="translatable attribute">not translatable</p>
<p i18n>translatable element <b>with placeholders</b> {{ interpolation}}</p>
<!-- i18n -->{ count, plural, =0 {<p>test</p>}}<!-- /i18n -->
<p i18n="m|d@@i">foo</p>
<p i18n="nested"><b><u>{{interpolation}} Text</u></b></p>
<p i18n="ph names"><br><img src="1.jpg"><img src="2.jpg"></p>
<p i18n="empty element">hello <span></span></p>
<p i18n="@@baz">{ count, plural, =0 { { sex, select, other {<p>deeply nested</p>}} }}</p>
<p i18n>{ count, plural, =0 { { sex, select, other {<p>deeply nested</p>}} }}</p>
`;
const WRITE_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en">
<file original="ng.template" id="ngi18n">
<unit id="1933478729560469763">
<segment>
<source>translatable attribute</source>
</segment>
</unit>
<unit id="7056919470098446707">
<segment>
<source>translatable element <pc id="0" equivStart="START_BOLD_TEXT" equivEnd="CLOSE_BOLD_TEXT" type="fmt" dispStart="&lt;b&gt;" dispEnd="&lt;/b&gt;">with placeholders</pc> <ph id="1" equiv="INTERPOLATION" disp="{{ interpolation}}"/></source>
</segment>
</unit>
<unit id="2981514368455622387">
<segment>
<source>{VAR_PLURAL, plural, =0 {<pc id="0" equivStart="START_PARAGRAPH" equivEnd="CLOSE_PARAGRAPH" type="other" dispStart="&lt;p&gt;" dispEnd="&lt;/p&gt;">test</pc>} }</source>
</segment>
</unit>
<unit id="i">
<notes>
<note category="description">d</note>
<note category="meaning">m</note>
</notes>
<segment>
<source>foo</source>
</segment>
</unit>
<unit id="6440235004920703622">
<notes>
<note category="description">nested</note>
</notes>
<segment>
<source><pc id="0" equivStart="START_BOLD_TEXT" equivEnd="CLOSE_BOLD_TEXT" type="fmt" dispStart="&lt;b&gt;" dispEnd="&lt;/b&gt;"><pc id="1" equivStart="START_UNDERLINED_TEXT" equivEnd="CLOSE_UNDERLINED_TEXT" type="fmt" dispStart="&lt;u&gt;" dispEnd="&lt;/u&gt;"><ph id="2" equiv="INTERPOLATION" disp="{{interpolation}}"/> Text</pc></pc></source>
</segment>
</unit>
<unit id="8779402634269838862">
<notes>
<note category="description">ph names</note>
</notes>
<segment>
<source><ph id="0" equiv="LINE_BREAK" type="fmt" disp="&lt;br/&gt;"/><ph id="1" equiv="TAG_IMG" type="image" disp="&lt;img/&gt;"/><ph id="2" equiv="TAG_IMG_1" type="image" disp="&lt;img/&gt;"/></source>
</segment>
</unit>
<unit id="6536355551500405293">
<notes>
<note category="description">empty element</note>
</notes>
<segment>
<source>hello <pc id="0" equivStart="START_TAG_SPAN" equivEnd="CLOSE_TAG_SPAN" type="other" dispStart="&lt;span&gt;" dispEnd="&lt;/span&gt;"></pc></source>
</segment>
</unit>
<unit id="baz">
<segment>
<source>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<pc id="0" equivStart="START_PARAGRAPH" equivEnd="CLOSE_PARAGRAPH" type="other" dispStart="&lt;p&gt;" dispEnd="&lt;/p&gt;">deeply nested</pc>} } } }</source>
</segment>
</unit>
<unit id="2015957479576096115">
<segment>
<source>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<pc id="0" equivStart="START_PARAGRAPH" equivEnd="CLOSE_PARAGRAPH" type="other" dispStart="&lt;p&gt;" dispEnd="&lt;/p&gt;">deeply nested</pc>} } } }</source>
</segment>
</unit>
</file>
</xliff>
`;
const LOAD_XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en" trgLang="fr">
<file original="ng.template" id="ngi18n">
<unit id="1933478729560469763">
<segment>
<source>translatable attribute</source>
<target>etubirtta elbatalsnart</target>
</segment>
</unit>
<unit id="7056919470098446707">
<segment>
<source>translatable element <pc id="0" equivStart="START_BOLD_TEXT" equivEnd="CLOSE_BOLD_TEXT" type="fmt" dispStart="&lt;b&gt;" dispEnd="&lt;/b&gt;">with placeholders</pc> <ph id="1" equiv="INTERPOLATION" disp="{{ interpolation}}"/></source>
<target><ph id="1" equiv="INTERPOLATION" disp="{{ interpolation}}"/> <pc id="0" equivStart="START_BOLD_TEXT" equivEnd="CLOSE_BOLD_TEXT" type="fmt" dispStart="&lt;b&gt;" dispEnd="&lt;/b&gt;">sredlohecalp htiw</pc> tnemele elbatalsnart</target>
</segment>
</unit>
<unit id="2981514368455622387">
<segment>
<source>{VAR_PLURAL, plural, =0 {<pc id="0" equivStart="START_PARAGRAPH" equivEnd="CLOSE_PARAGRAPH" type="other" dispStart="&lt;p&gt;" dispEnd="&lt;/p&gt;">test</pc>} }</source>
<target>{VAR_PLURAL, plural, =0 {<pc id="0" equivStart="START_PARAGRAPH" equivEnd="CLOSE_PARAGRAPH" type="other" dispStart="&lt;p&gt;" dispEnd="&lt;/p&gt;">TEST</pc>} }</target>
</segment>
</unit>
<unit id="i">
<notes>
<note category="description">d</note>
<note category="meaning">m</note>
</notes>
<segment>
<source>foo</source>
<target>oof</target>
</segment>
</unit>
<unit id="6440235004920703622">
<notes>
<note category="description">nested</note>
</notes>
<segment>
<source><pc id="0" equivStart="START_BOLD_TEXT" equivEnd="CLOSE_BOLD_TEXT" type="fmt" dispStart="&lt;b&gt;" dispEnd="&lt;/b&gt;"><pc id="1" equivStart="START_UNDERLINED_TEXT" equivEnd="CLOSE_UNDERLINED_TEXT" type="fmt" dispStart="&lt;u&gt;" dispEnd="&lt;/u&gt;"><ph id="2" equiv="INTERPOLATION" disp="{{interpolation}}"/> Text</pc></pc></source>
<target><pc id="0" equivStart="START_BOLD_TEXT" equivEnd="CLOSE_BOLD_TEXT" type="fmt" dispStart="&lt;b&gt;" dispEnd="&lt;/b&gt;"><pc id="1" equivStart="START_UNDERLINED_TEXT" equivEnd="CLOSE_UNDERLINED_TEXT" type="fmt" dispStart="&lt;u&gt;" dispEnd="&lt;/u&gt;">txeT <ph id="2" equiv="INTERPOLATION" disp="{{interpolation}}"/></pc></pc></target>
</segment>
</unit>
<unit id="8779402634269838862">
<notes>
<note category="description">ph names</note>
</notes>
<segment>
<source><ph id="0" equiv="LINE_BREAK" type="fmt" disp="&lt;br/&gt;"/><ph id="1" equiv="TAG_IMG" type="image" disp="&lt;img/&gt;"/><ph id="2" equiv="TAG_IMG_1" type="image" disp="&lt;img/&gt;"/></source>
<target><ph id="2" equiv="TAG_IMG_1" type="image" disp="&lt;img/&gt;"/><ph id="1" equiv="TAG_IMG" type="image" disp="&lt;img/&gt;"/><ph id="0" equiv="LINE_BREAK" type="fmt" disp="&lt;br/&gt;"/></target>
</segment>
</unit>
<unit id="6536355551500405293">
<notes>
<note category="description">empty element</note>
</notes>
<segment>
<source>hello <pc id="0" equivStart="START_TAG_SPAN" equivEnd="CLOSE_TAG_SPAN" type="other" dispStart="&lt;span&gt;" dispEnd="&lt;/span&gt;"></pc></source>
<target><pc id="0" equivStart="START_TAG_SPAN" equivEnd="CLOSE_TAG_SPAN" type="other" dispStart="&lt;span&gt;" dispEnd="&lt;/span&gt;"></pc> olleh</target>
</segment>
</unit>
<unit id="baz">
<segment>
<source>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<pc id="0" equivStart="START_PARAGRAPH" equivEnd="CLOSE_PARAGRAPH" type="other" dispStart="&lt;p&gt;" dispEnd="&lt;/p&gt;">deeply nested</pc>} } } }</source>
<target>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<pc id="0" equivStart="START_PARAGRAPH" equivEnd="CLOSE_PARAGRAPH" type="other" dispStart="&lt;p&gt;" dispEnd="&lt;/p&gt;">profondément imbriqué</pc>} } } }</target>
</segment>
</unit>
<unit id="2015957479576096115">
<segment>
<source>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<pc id="0" equivStart="START_PARAGRAPH" equivEnd="CLOSE_PARAGRAPH" type="other" dispStart="&lt;p&gt;" dispEnd="&lt;/p&gt;">deeply nested</pc>} } } }</source>
<target>{VAR_PLURAL, plural, =0 {{VAR_SELECT, select, other {<pc id="0" equivStart="START_PARAGRAPH" equivEnd="CLOSE_PARAGRAPH" type="other" dispStart="&lt;p&gt;" dispEnd="&lt;/p&gt;">profondément imbriqué</pc>} } } }</target>
</segment>
</unit>
</file>
</xliff>
`;
export function main(): void {
const serializer = new Xliff2();
function toXliff(html: string, locale: string | null = null): string {
const catalog = new MessageBundle(new HtmlParser, [], {}, locale);
catalog.updateFromTemplate(html, '', DEFAULT_INTERPOLATION_CONFIG);
return catalog.write(serializer);
}
function loadAsMap(xliff: string): {[id: string]: string} {
const {i18nNodesByMsgId} = serializer.load(xliff, 'url');
const msgMap: {[id: string]: string} = {};
Object.keys(i18nNodesByMsgId)
.forEach(id => msgMap[id] = serializeNodes(i18nNodesByMsgId[id]).join(''));
return msgMap;
}
describe('XLIFF 2.0 serializer', () => {
describe('write', () => {
it('should write a valid xliff 2.0 file',
() => { expect(toXliff(HTML)).toEqual(WRITE_XLIFF); });
it('should write a valid xliff 2.0 file with a source language',
() => { expect(toXliff(HTML, 'fr')).toContain('srcLang="fr"'); });
});
describe('load', () => {
it('should load XLIFF files', () => {
expect(loadAsMap(LOAD_XLIFF)).toEqual({
'1933478729560469763': 'etubirtta elbatalsnart',
'7056919470098446707':
'<ph name="INTERPOLATION"/> <ph name="START_BOLD_TEXT"/>sredlohecalp htiw<ph name="CLOSE_BOLD_TEXT"/> tnemele elbatalsnart',
'2981514368455622387':
'{VAR_PLURAL, plural, =0 {[<ph name="START_PARAGRAPH"/>, TEST, <ph name="CLOSE_PARAGRAPH"/>]}}',
'i': 'oof',
'6440235004920703622':
'<ph name="START_BOLD_TEXT"/><ph name="START_UNDERLINED_TEXT"/>txeT <ph name="INTERPOLATION"/><ph name="CLOSE_UNDERLINED_TEXT"/><ph name="CLOSE_BOLD_TEXT"/>',
'8779402634269838862':
'<ph name="TAG_IMG_1"/><ph name="TAG_IMG"/><ph name="LINE_BREAK"/>',
'6536355551500405293': '<ph name="START_TAG_SPAN"/><ph name="CLOSE_TAG_SPAN"/> olleh',
'baz':
'{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}}',
'2015957479576096115':
'{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}}'
});
});
it('should return the target locale',
() => { expect(serializer.load(LOAD_XLIFF, 'url').locale).toEqual('fr'); });
});
describe('structure errors', () => {
it('should throw when a wrong xliff version is used', () => {
const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="ng2.template">
<body>
<trans-unit id="deadbeef">
<source/>
<target/>
</trans-unit>
</body>
</file>
</xliff>`;
expect(() => {
loadAsMap(XLIFF);
}).toThrowError(/The XLIFF file version 1.2 is not compatible with XLIFF 2.0 serializer/);
});
it('should throw when an unit has no translation', () => {
const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en">
<file original="ng.template" id="ngi18n">
<unit id="missingtarget">
<segment>
<source/>
</segment>
</unit>
</file>
</xliff>`;
expect(() => {
loadAsMap(XLIFF);
}).toThrowError(/Message missingtarget misses a translation/);
});
it('should throw when an unit has no id attribute', () => {
const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en">
<file original="ng.template" id="ngi18n">
<unit>
<segment>
<source/>
<target/>
</segment>
</unit>
</file>
</xliff>`;
expect(() => { loadAsMap(XLIFF); }).toThrowError(/<unit> misses the "id" attribute/);
});
it('should throw on duplicate unit id', () => {
const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en">
<file original="ng.template" id="ngi18n">
<unit id="deadbeef">
<segment>
<source/>
<target/>
</segment>
</unit>
<unit id="deadbeef">
<segment>
<source/>
<target/>
</segment>
</unit>
</file>
</xliff>`;
expect(() => {
loadAsMap(XLIFF);
}).toThrowError(/Duplicated translations for msg deadbeef/);
});
});
describe('message errors', () => {
it('should throw on unknown message tags', () => {
const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en">
<file original="ng.template" id="ngi18n">
<unit id="deadbeef">
<segment>
<source/>
<target><b>msg should contain only ph and pc tags</b></target>
</segment>
</unit>
</file>
</xliff>`;
expect(() => { loadAsMap(XLIFF); })
.toThrowError(new RegExp(
escapeRegExp(`[ERROR ->]<b>msg should contain only ph and pc tags</b>`)));
});
it('should throw when a placeholder misses an id attribute', () => {
const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en">
<file original="ng.template" id="ngi18n">
<unit id="deadbeef">
<segment>
<source/>
<target><ph/></target>
</segment>
</unit>
</file>
</xliff>`;
expect(() => {
loadAsMap(XLIFF);
}).toThrowError(new RegExp(escapeRegExp(`<ph> misses the "equiv" attribute`)));
});
});
});
}

View File

@ -62,7 +62,7 @@ export interface AnimationStyleMetadata extends AnimationMetadata {
*/
export interface AnimationAnimateMetadata extends AnimationMetadata {
timings: string|number|AnimateTimings;
styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata;
styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata|null;
}
/**
@ -86,8 +86,8 @@ export function trigger(name: string, definitions: AnimationMetadata[]): Animati
* @deprecated This symbol has moved. Please Import from @angular/animations instead!
*/
export function animate(
timings: string | number, styles: AnimationStyleMetadata | AnimationKeyframesSequenceMetadata =
null): AnimationAnimateMetadata {
timings: string | number, styles?: AnimationStyleMetadata |
AnimationKeyframesSequenceMetadata): AnimationAnimateMetadata {
return _animate(timings, styles);
}

View File

@ -99,7 +99,7 @@ export function createPlatform(injector: Injector): PlatformRef {
* @experimental APIs related to application bootstrap are currently under review.
*/
export function createPlatformFactory(
parentPlatformFactory: (extraProviders?: Provider[]) => PlatformRef, name: string,
parentPlatformFactory: ((extraProviders?: Provider[]) => PlatformRef) | null, name: string,
providers: Provider[] = []): (extraProviders?: Provider[]) => PlatformRef {
const marker = new InjectionToken(`Platform: ${name}`);
return (extraProviders: Provider[] = []) => {
@ -153,7 +153,7 @@ export function destroyPlatform(): void {
*
* @experimental APIs related to application bootstrap are currently under review.
*/
export function getPlatform(): PlatformRef {
export function getPlatform(): PlatformRef|null {
return _platform && !_platform.destroyed ? _platform : null;
}
@ -278,10 +278,10 @@ export class PlatformRef_ extends PlatformRef {
}
bootstrapModuleFactory<M>(moduleFactory: NgModuleFactory<M>): Promise<NgModuleRef<M>> {
return this._bootstrapModuleFactoryWithZone(moduleFactory, null);
return this._bootstrapModuleFactoryWithZone(moduleFactory);
}
private _bootstrapModuleFactoryWithZone<M>(moduleFactory: NgModuleFactory<M>, ngZone: NgZone):
private _bootstrapModuleFactoryWithZone<M>(moduleFactory: NgModuleFactory<M>, ngZone?: NgZone):
Promise<NgModuleRef<M>> {
// Note: We need to create the NgZone _before_ we instantiate the module,
// as instantiating the module creates some providers eagerly.
@ -299,7 +299,7 @@ export class PlatformRef_ extends PlatformRef {
throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?');
}
moduleRef.onDestroy(() => remove(this._modules, moduleRef));
ngZone.onError.subscribe({next: (error: any) => { exceptionHandler.handleError(error); }});
ngZone !.onError.subscribe({next: (error: any) => { exceptionHandler.handleError(error); }});
return _callAndReportToErrorHandler(exceptionHandler, () => {
const initStatus: ApplicationInitStatus = moduleRef.injector.get(ApplicationInitStatus);
return initStatus.donePromise.then(() => {
@ -312,12 +312,12 @@ export class PlatformRef_ extends PlatformRef {
bootstrapModule<M>(moduleType: Type<M>, compilerOptions: CompilerOptions|CompilerOptions[] = []):
Promise<NgModuleRef<M>> {
return this._bootstrapModuleWithZone(moduleType, compilerOptions, null);
return this._bootstrapModuleWithZone(moduleType, compilerOptions);
}
private _bootstrapModuleWithZone<M>(
moduleType: Type<M>, compilerOptions: CompilerOptions|CompilerOptions[] = [],
ngZone: NgZone = null): Promise<NgModuleRef<M>> {
ngZone?: NgZone): Promise<NgModuleRef<M>> {
const compilerFactory: CompilerFactory = this.injector.get(CompilerFactory);
const compiler = compilerFactory.createCompiler(
Array.isArray(compilerOptions) ? compilerOptions : [compilerOptions]);
@ -500,7 +500,8 @@ export class ApplicationRef_ extends ApplicationRef {
if (componentOrFactory instanceof ComponentFactory) {
componentFactory = componentOrFactory;
} else {
componentFactory = this._componentFactoryResolver.resolveComponentFactory(componentOrFactory);
componentFactory =
this._componentFactoryResolver.resolveComponentFactory(componentOrFactory) !;
}
this._rootComponentTypes.push(componentFactory.componentType);

View File

@ -15,16 +15,15 @@ import {IterableChangeRecord, IterableChanges, IterableDiffer, IterableDifferFac
export class DefaultIterableDifferFactory implements IterableDifferFactory {
constructor() {}
supports(obj: Object): boolean { return isListLikeIterable(obj); }
supports(obj: Object|null|undefined): boolean { return isListLikeIterable(obj); }
create<V>(trackByFn?: TrackByFunction<any>): DefaultIterableDiffer<V>;
create<V>(trackByFn?: TrackByFunction<V>): DefaultIterableDiffer<V>;
/**
* @deprecated v4.0.0 - ChangeDetectorRef is not used and is no longer a parameter
*/
create<V>(
cdRefOrTrackBy?: ChangeDetectorRef|TrackByFunction<any>,
trackByFn?: TrackByFunction<any>): DefaultIterableDiffer<V> {
create<V>(cdRefOrTrackBy?: ChangeDetectorRef|TrackByFunction<V>, trackByFn?: TrackByFunction<V>):
DefaultIterableDiffer<V> {
return new DefaultIterableDiffer<V>(trackByFn || <TrackByFunction<any>>cdRefOrTrackBy);
}
}
@ -35,27 +34,28 @@ const trackByIdentity = (index: number, item: any) => item;
* @deprecated v4.0.0 - Should not be part of public API.
*/
export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChanges<V> {
private _length: number = null;
private _collection: NgIterable<V> = null;
private _length: number = 0;
private _collection: NgIterable<V>|null = null;
// Keeps track of the used records at any point in time (during & across `_check()` calls)
private _linkedRecords: _DuplicateMap<V> = null;
private _linkedRecords: _DuplicateMap<V>|null = null;
// Keeps track of the removed records at any point in time during `_check()` calls.
private _unlinkedRecords: _DuplicateMap<V> = null;
private _previousItHead: IterableChangeRecord_<V> = null;
private _itHead: IterableChangeRecord_<V> = null;
private _itTail: IterableChangeRecord_<V> = null;
private _additionsHead: IterableChangeRecord_<V> = null;
private _additionsTail: IterableChangeRecord_<V> = null;
private _movesHead: IterableChangeRecord_<V> = null;
private _movesTail: IterableChangeRecord_<V> = null;
private _removalsHead: IterableChangeRecord_<V> = null;
private _removalsTail: IterableChangeRecord_<V> = null;
private _unlinkedRecords: _DuplicateMap<V>|null = null;
private _previousItHead: IterableChangeRecord_<V>|null = null;
private _itHead: IterableChangeRecord_<V>|null = null;
private _itTail: IterableChangeRecord_<V>|null = null;
private _additionsHead: IterableChangeRecord_<V>|null = null;
private _additionsTail: IterableChangeRecord_<V>|null = null;
private _movesHead: IterableChangeRecord_<V>|null = null;
private _movesTail: IterableChangeRecord_<V>|null = null;
private _removalsHead: IterableChangeRecord_<V>|null = null;
private _removalsTail: IterableChangeRecord_<V>|null = null;
// Keeps track of records where custom track by is the same, but item identity has changed
private _identityChangesHead: IterableChangeRecord_<V> = null;
private _identityChangesTail: IterableChangeRecord_<V> = null;
private _identityChangesHead: IterableChangeRecord_<V>|null = null;
private _identityChangesTail: IterableChangeRecord_<V>|null = null;
private _trackByFn: TrackByFunction<V>
constructor(private _trackByFn?: TrackByFunction<V>) {
this._trackByFn = this._trackByFn || trackByIdentity;
constructor(trackByFn?: TrackByFunction<V>) {
this._trackByFn = trackByFn || trackByIdentity;
}
get collection() { return this._collection; }
@ -63,25 +63,27 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
get length(): number { return this._length; }
forEachItem(fn: (record: IterableChangeRecord_<V>) => void) {
let record: IterableChangeRecord_<V>;
let record: IterableChangeRecord_<V>|null;
for (record = this._itHead; record !== null; record = record._next) {
fn(record);
}
}
forEachOperation(
fn: (item: IterableChangeRecord_<V>, previousIndex: number, currentIndex: number) => void) {
fn: (item: IterableChangeRecord<V>, previousIndex: number|null, currentIndex: number|null) =>
void) {
let nextIt = this._itHead;
let nextRemove = this._removalsHead;
let addRemoveOffset = 0;
let moveOffsets: number[] = null;
let moveOffsets: number[]|null = null;
while (nextIt || nextRemove) {
// Figure out which is the next record to process
// Order: remove, add, move
const record = !nextRemove ||
const record: IterableChangeRecord<V> = !nextRemove ||
nextIt &&
nextIt.currentIndex < getPreviousIndex(nextRemove, addRemoveOffset, moveOffsets) ?
nextIt :
nextIt.currentIndex ! <
getPreviousIndex(nextRemove, addRemoveOffset, moveOffsets) ?
nextIt ! :
nextRemove;
const adjPreviousIndex = getPreviousIndex(record, addRemoveOffset, moveOffsets);
const currentIndex = record.currentIndex;
@ -91,14 +93,14 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
addRemoveOffset--;
nextRemove = nextRemove._nextRemoved;
} else {
nextIt = nextIt._next;
nextIt = nextIt !._next;
if (record.previousIndex == null) {
addRemoveOffset++;
} else {
// INVARIANT: currentIndex < previousIndex
if (!moveOffsets) moveOffsets = [];
const localMovePreviousIndex = adjPreviousIndex - addRemoveOffset;
const localCurrentIndex = currentIndex - addRemoveOffset;
const localCurrentIndex = currentIndex ! - addRemoveOffset;
if (localMovePreviousIndex != localCurrentIndex) {
for (let i = 0; i < localMovePreviousIndex; i++) {
const offset = i < moveOffsets.length ? moveOffsets[i] : (moveOffsets[i] = 0);
@ -120,44 +122,45 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
}
forEachPreviousItem(fn: (record: IterableChangeRecord_<V>) => void) {
let record: IterableChangeRecord_<V>;
let record: IterableChangeRecord_<V>|null;
for (record = this._previousItHead; record !== null; record = record._nextPrevious) {
fn(record);
}
}
forEachAddedItem(fn: (record: IterableChangeRecord_<V>) => void) {
let record: IterableChangeRecord_<V>;
let record: IterableChangeRecord_<V>|null;
for (record = this._additionsHead; record !== null; record = record._nextAdded) {
fn(record);
}
}
forEachMovedItem(fn: (record: IterableChangeRecord_<V>) => void) {
let record: IterableChangeRecord_<V>;
let record: IterableChangeRecord_<V>|null;
for (record = this._movesHead; record !== null; record = record._nextMoved) {
fn(record);
}
}
forEachRemovedItem(fn: (record: IterableChangeRecord_<V>) => void) {
let record: IterableChangeRecord_<V>;
let record: IterableChangeRecord_<V>|null;
for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
fn(record);
}
}
forEachIdentityChange(fn: (record: IterableChangeRecord_<V>) => void) {
let record: IterableChangeRecord_<V>;
let record: IterableChangeRecord_<V>|null;
for (record = this._identityChangesHead; record !== null; record = record._nextIdentityChange) {
fn(record);
}
}
diff(collection: NgIterable<V>): DefaultIterableDiffer<V> {
diff(collection: NgIterable<V>): DefaultIterableDiffer<V>|null {
if (collection == null) collection = [];
if (!isListLikeIterable(collection)) {
throw new Error(`Error trying to diff '${collection}'`);
throw new Error(
`Error trying to diff '${stringify(collection)}'. Only arrays and iterables are allowed`);
}
if (this.check(collection)) {
@ -173,7 +176,7 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
check(collection: NgIterable<V>): boolean {
this._reset();
let record: IterableChangeRecord_<V> = this._itHead;
let record: IterableChangeRecord_<V>|null = this._itHead;
let mayBeDirty: boolean = false;
let index: number;
let item: V;
@ -240,8 +243,8 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
*/
_reset() {
if (this.isDirty) {
let record: IterableChangeRecord_<V>;
let nextRecord: IterableChangeRecord_<V>;
let record: IterableChangeRecord_<V>|null;
let nextRecord: IterableChangeRecord_<V>|null;
for (record = this._previousItHead = this._itHead; record !== null; record = record._next) {
record._nextPrevious = record._next;
@ -275,15 +278,15 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
*
* @internal
*/
_mismatch(record: IterableChangeRecord_<V>, item: V, itemTrackBy: any, index: number):
_mismatch(record: IterableChangeRecord_<V>|null, item: V, itemTrackBy: any, index: number):
IterableChangeRecord_<V> {
// The previous record after which we will append the current one.
let previousRecord: IterableChangeRecord_<V>;
if (record === null) {
previousRecord = this._itTail;
previousRecord = this._itTail !;
} else {
previousRecord = record._prev;
previousRecord = record._prev !;
// Remove the record from the collection since we know it does not match the item.
this._remove(record);
}
@ -298,7 +301,7 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
this._moveAfter(record, previousRecord, index);
} else {
// Never seen it, check evicted list.
record = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy);
record = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
if (record !== null) {
// It is an item which we have evicted earlier: reinsert it back into the list.
// But first we need to check if identity changed, so we can update in view if necessary
@ -343,10 +346,10 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
*/
_verifyReinsertion(record: IterableChangeRecord_<V>, item: V, itemTrackBy: any, index: number):
IterableChangeRecord_<V> {
let reinsertRecord: IterableChangeRecord_<V> =
this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy);
let reinsertRecord: IterableChangeRecord_<V>|null =
this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null);
if (reinsertRecord !== null) {
record = this._reinsertAfter(reinsertRecord, record._prev, index);
record = this._reinsertAfter(reinsertRecord, record._prev !, index);
} else if (record.currentIndex != index) {
record.currentIndex = index;
this._addToMoves(record, index);
@ -361,10 +364,10 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
*
* @internal
*/
_truncate(record: IterableChangeRecord_<V>) {
_truncate(record: IterableChangeRecord_<V>|null) {
// Anything after that needs to be removed;
while (record !== null) {
const nextRecord: IterableChangeRecord_<V> = record._next;
const nextRecord: IterableChangeRecord_<V>|null = record._next;
this._addToRemovals(this._unlink(record));
record = nextRecord;
}
@ -451,7 +454,8 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
// assert(record._next === null);
// assert(record._prev === null);
const next: IterableChangeRecord_<V> = prevRecord === null ? this._itHead : prevRecord._next;
const next: IterableChangeRecord_<V>|null =
prevRecord === null ? this._itHead : prevRecord._next;
// todo(vicb)
// assert(next != record);
// assert(prevRecord != record);
@ -598,29 +602,29 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan
* @stable
*/
export class IterableChangeRecord_<V> implements IterableChangeRecord<V> {
currentIndex: number = null;
previousIndex: number = null;
currentIndex: number|null = null;
previousIndex: number|null = null;
/** @internal */
_nextPrevious: IterableChangeRecord_<V> = null;
_nextPrevious: IterableChangeRecord_<V>|null = null;
/** @internal */
_prev: IterableChangeRecord_<V> = null;
_prev: IterableChangeRecord_<V>|null = null;
/** @internal */
_next: IterableChangeRecord_<V> = null;
_next: IterableChangeRecord_<V>|null = null;
/** @internal */
_prevDup: IterableChangeRecord_<V> = null;
_prevDup: IterableChangeRecord_<V>|null = null;
/** @internal */
_nextDup: IterableChangeRecord_<V> = null;
_nextDup: IterableChangeRecord_<V>|null = null;
/** @internal */
_prevRemoved: IterableChangeRecord_<V> = null;
_prevRemoved: IterableChangeRecord_<V>|null = null;
/** @internal */
_nextRemoved: IterableChangeRecord_<V> = null;
_nextRemoved: IterableChangeRecord_<V>|null = null;
/** @internal */
_nextAdded: IterableChangeRecord_<V> = null;
_nextAdded: IterableChangeRecord_<V>|null = null;
/** @internal */
_nextMoved: IterableChangeRecord_<V> = null;
_nextMoved: IterableChangeRecord_<V>|null = null;
/** @internal */
_nextIdentityChange: IterableChangeRecord_<V> = null;
_nextIdentityChange: IterableChangeRecord_<V>|null = null;
constructor(public item: V, public trackById: any) {}
@ -635,9 +639,9 @@ export class IterableChangeRecord_<V> implements IterableChangeRecord<V> {
// A linked list of CollectionChangeRecords with the same IterableChangeRecord_.item
class _DuplicateItemRecordList<V> {
/** @internal */
_head: IterableChangeRecord_<V> = null;
_head: IterableChangeRecord_<V>|null = null;
/** @internal */
_tail: IterableChangeRecord_<V> = null;
_tail: IterableChangeRecord_<V>|null = null;
/**
* Append the record to the list of duplicates.
@ -653,7 +657,7 @@ class _DuplicateItemRecordList<V> {
// todo(vicb)
// assert(record.item == _head.item ||
// record.item is num && record.item.isNaN && _head.item is num && _head.item.isNaN);
this._tail._nextDup = record;
this._tail !._nextDup = record;
record._prevDup = this._tail;
record._nextDup = null;
this._tail = record;
@ -662,8 +666,8 @@ class _DuplicateItemRecordList<V> {
// Returns a IterableChangeRecord_ having IterableChangeRecord_.trackById == trackById and
// IterableChangeRecord_.currentIndex >= afterIndex
get(trackById: any, afterIndex: number): IterableChangeRecord_<V> {
let record: IterableChangeRecord_<V>;
get(trackById: any, afterIndex: number|null): IterableChangeRecord_<V>|null {
let record: IterableChangeRecord_<V>|null;
for (record = this._head; record !== null; record = record._nextDup) {
if ((afterIndex === null || afterIndex < record.currentIndex) &&
looseIdentical(record.trackById, trackById)) {
@ -688,8 +692,8 @@ class _DuplicateItemRecordList<V> {
// return false;
//});
const prev: IterableChangeRecord_<V> = record._prevDup;
const next: IterableChangeRecord_<V> = record._nextDup;
const prev: IterableChangeRecord_<V>|null = record._prevDup;
const next: IterableChangeRecord_<V>|null = record._nextDup;
if (prev === null) {
this._head = next;
} else {
@ -725,7 +729,7 @@ class _DuplicateMap<V> {
* Use case: `[a, b, c, a, a]` if we are at index `3` which is the second `a` then asking if we
* have any more `a`s needs to return the last `a` not the first or second.
*/
get(trackById: any, afterIndex: number = null): IterableChangeRecord_<V> {
get(trackById: any, afterIndex: number|null): IterableChangeRecord_<V>|null {
const key = trackById;
const recordList = this.map.get(key);
return recordList ? recordList.get(trackById, afterIndex) : null;
@ -738,7 +742,7 @@ class _DuplicateMap<V> {
*/
remove(record: IterableChangeRecord_<V>): IterableChangeRecord_<V> {
const key = record.trackById;
const recordList: _DuplicateItemRecordList<V> = this.map.get(key);
const recordList: _DuplicateItemRecordList<V> = this.map.get(key) !;
// Remove the list of duplicates when it gets empty
if (recordList.remove(record)) {
this.map.delete(key);
@ -753,7 +757,8 @@ class _DuplicateMap<V> {
toString(): string { return '_DuplicateMap(' + stringify(this.map) + ')'; }
}
function getPreviousIndex(item: any, addRemoveOffset: number, moveOffsets: number[]): number {
function getPreviousIndex(
item: any, addRemoveOffset: number, moveOffsets: number[] | null): number {
const previousIndex = item.previousIndex;
if (previousIndex === null) return previousIndex;
let moveOffset = 0;

View File

@ -9,7 +9,6 @@
import {looseIdentical, stringify} from '../../util';
import {isJsObject} from '../change_detection_util';
import {ChangeDetectorRef} from '../change_detector_ref';
import {KeyValueChangeRecord, KeyValueChanges, KeyValueDiffer, KeyValueDifferFactory} from './keyvalue_differs';
@ -28,15 +27,17 @@ export class DefaultKeyValueDifferFactory<K, V> implements KeyValueDifferFactory
}
export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyValueChanges<K, V> {
private _records: Map<K, V> = new Map<K, V>();
private _mapHead: KeyValueChangeRecord_<K, V> = null;
private _previousMapHead: KeyValueChangeRecord_<K, V> = null;
private _changesHead: KeyValueChangeRecord_<K, V> = null;
private _changesTail: KeyValueChangeRecord_<K, V> = null;
private _additionsHead: KeyValueChangeRecord_<K, V> = null;
private _additionsTail: KeyValueChangeRecord_<K, V> = null;
private _removalsHead: KeyValueChangeRecord_<K, V> = null;
private _removalsTail: KeyValueChangeRecord_<K, V> = null;
private _records = new Map<K, KeyValueChangeRecord_<K, V>>();
private _mapHead: KeyValueChangeRecord_<K, V>|null = null;
// _appendAfter is used in the check loop
private _appendAfter: KeyValueChangeRecord_<K, V>|null = null;
private _previousMapHead: KeyValueChangeRecord_<K, V>|null = null;
private _changesHead: KeyValueChangeRecord_<K, V>|null = null;
private _changesTail: KeyValueChangeRecord_<K, V>|null = null;
private _additionsHead: KeyValueChangeRecord_<K, V>|null = null;
private _additionsTail: KeyValueChangeRecord_<K, V>|null = null;
private _removalsHead: KeyValueChangeRecord_<K, V>|null = null;
private _removalsTail: KeyValueChangeRecord_<K, V>|null = null;
get isDirty(): boolean {
return this._additionsHead !== null || this._changesHead !== null ||
@ -44,45 +45,46 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
}
forEachItem(fn: (r: KeyValueChangeRecord<K, V>) => void) {
let record: KeyValueChangeRecord_<K, V>;
let record: KeyValueChangeRecord_<K, V>|null;
for (record = this._mapHead; record !== null; record = record._next) {
fn(record);
}
}
forEachPreviousItem(fn: (r: KeyValueChangeRecord<K, V>) => void) {
let record: KeyValueChangeRecord_<K, V>;
let record: KeyValueChangeRecord_<K, V>|null;
for (record = this._previousMapHead; record !== null; record = record._nextPrevious) {
fn(record);
}
}
forEachChangedItem(fn: (r: KeyValueChangeRecord<K, V>) => void) {
let record: KeyValueChangeRecord_<K, V>;
let record: KeyValueChangeRecord_<K, V>|null;
for (record = this._changesHead; record !== null; record = record._nextChanged) {
fn(record);
}
}
forEachAddedItem(fn: (r: KeyValueChangeRecord<K, V>) => void) {
let record: KeyValueChangeRecord_<K, V>;
let record: KeyValueChangeRecord_<K, V>|null;
for (record = this._additionsHead; record !== null; record = record._nextAdded) {
fn(record);
}
}
forEachRemovedItem(fn: (r: KeyValueChangeRecord<K, V>) => void) {
let record: KeyValueChangeRecord_<K, V>;
let record: KeyValueChangeRecord_<K, V>|null;
for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
fn(record);
}
}
diff(map: Map<any, any>|{[k: string]: any}): any {
diff(map?: Map<any, any>|{[k: string]: any}|null): any {
if (!map) {
map = new Map();
} else if (!(map instanceof Map || isJsObject(map))) {
throw new Error(`Error trying to diff '${map}'`);
throw new Error(
`Error trying to diff '${stringify(map)}'. Only maps and objects are allowed`);
}
return this.check(map) ? this : null;
@ -90,98 +92,144 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
onDestroy() {}
/**
* Check the current state of the map vs the previous.
* The algorithm is optimised for when the keys do no change.
*/
check(map: Map<any, any>|{[k: string]: any}): boolean {
this._reset();
const records = this._records;
let oldSeqRecord: KeyValueChangeRecord_<K, V> = this._mapHead;
let lastOldSeqRecord: KeyValueChangeRecord_<K, V> = null;
let lastNewSeqRecord: KeyValueChangeRecord_<K, V> = null;
let seqChanged: boolean = false;
let insertBefore = this._mapHead;
this._appendAfter = null;
this._forEach(map, (value: any, key: any) => {
let newSeqRecord: any;
if (oldSeqRecord && key === oldSeqRecord.key) {
newSeqRecord = oldSeqRecord;
this._maybeAddToChanges(newSeqRecord, value);
if (insertBefore && insertBefore.key === key) {
this._maybeAddToChanges(insertBefore, value);
this._appendAfter = insertBefore;
insertBefore = insertBefore._next;
} else {
seqChanged = true;
if (oldSeqRecord !== null) {
this._removeFromSeq(lastOldSeqRecord, oldSeqRecord);
this._addToRemovals(oldSeqRecord);
}
if (records.has(key)) {
newSeqRecord = records.get(key);
this._maybeAddToChanges(newSeqRecord, value);
} else {
newSeqRecord = new KeyValueChangeRecord_<K, V>(key);
records.set(key, newSeqRecord);
newSeqRecord.currentValue = value;
this._addToAdditions(newSeqRecord);
}
const record = this._getOrCreateRecordForKey(key, value);
insertBefore = this._insertBeforeOrAppend(insertBefore, record);
}
});
// Items remaining at the end of the list have been deleted
if (insertBefore) {
if (insertBefore._prev) {
insertBefore._prev._next = null;
}
if (seqChanged) {
if (this._isInRemovals(newSeqRecord)) {
this._removeFromRemovals(newSeqRecord);
}
if (lastNewSeqRecord == null) {
this._mapHead = newSeqRecord;
} else {
lastNewSeqRecord._next = newSeqRecord;
this._removalsHead = insertBefore;
for (let record = insertBefore; record !== null; record = record._nextRemoved) {
if (record === this._mapHead) {
this._mapHead = null;
}
this._records.delete(record.key);
record._nextRemoved = record._next;
record.previousValue = record.currentValue;
record.currentValue = null;
record._prev = null;
record._next = null;
}
lastOldSeqRecord = oldSeqRecord;
lastNewSeqRecord = newSeqRecord;
oldSeqRecord = oldSeqRecord && oldSeqRecord._next;
});
this._truncate(lastOldSeqRecord, oldSeqRecord);
}
// Make sure tails have no next records from previous runs
if (this._changesTail) this._changesTail._nextChanged = null;
if (this._additionsTail) this._additionsTail._nextAdded = null;
return this.isDirty;
}
/**
* Inserts a record before `before` or append at the end of the list when `before` is null.
*
* Notes:
* - This method appends at `this._appendAfter`,
* - This method updates `this._appendAfter`,
* - The return value is the new value for the insertion pointer.
*/
private _insertBeforeOrAppend(
before: KeyValueChangeRecord_<K, V>,
record: KeyValueChangeRecord_<K, V>): KeyValueChangeRecord_<K, V> {
if (before) {
const prev = before._prev;
record._next = before;
record._prev = prev;
before._prev = record;
if (prev) {
prev._next = record;
}
if (before === this._mapHead) {
this._mapHead = record;
}
this._appendAfter = before;
return before;
}
if (this._appendAfter) {
this._appendAfter._next = record;
record._prev = this._appendAfter;
} else {
this._mapHead = record;
}
this._appendAfter = record;
return null;
}
private _getOrCreateRecordForKey(key: K, value: V): KeyValueChangeRecord_<K, V> {
if (this._records.has(key)) {
const record = this._records.get(key);
this._maybeAddToChanges(record, value);
const prev = record._prev;
const next = record._next;
if (prev) {
prev._next = next;
}
if (next) {
next._prev = prev;
}
record._next = null;
record._prev = null;
return record;
}
const record = new KeyValueChangeRecord_<K, V>(key);
this._records.set(key, record);
record.currentValue = value;
this._addToAdditions(record);
return record;
}
/** @internal */
_reset() {
if (this.isDirty) {
let record: KeyValueChangeRecord_<K, V>;
// Record the state of the mapping
for (record = this._previousMapHead = this._mapHead; record !== null; record = record._next) {
let record: KeyValueChangeRecord_<K, V>|null;
// let `_previousMapHead` contain the state of the map before the changes
this._previousMapHead = this._mapHead;
for (record = this._previousMapHead; record !== null; record = record._next) {
record._nextPrevious = record._next;
}
// Update `record.previousValue` with the value of the item before the changes
// We need to update all changed items (that's those which have been added and changed)
for (record = this._changesHead; record !== null; record = record._nextChanged) {
record.previousValue = record.currentValue;
}
for (record = this._additionsHead; record != null; record = record._nextAdded) {
record.previousValue = record.currentValue;
}
this._changesHead = this._changesTail = null;
this._additionsHead = this._additionsTail = null;
this._removalsHead = this._removalsTail = null;
}
}
private _truncate(lastRecord: KeyValueChangeRecord_<K, V>, record: KeyValueChangeRecord_<K, V>) {
while (record !== null) {
if (lastRecord === null) {
this._mapHead = null;
} else {
lastRecord._next = null;
}
const nextRecord = record._next;
this._addToRemovals(record);
lastRecord = record;
record = nextRecord;
}
for (let rec: KeyValueChangeRecord_<K, V> = this._removalsHead; rec !== null;
rec = rec._nextRemoved) {
rec.previousValue = rec.currentValue;
rec.currentValue = null;
this._records.delete(rec.key);
this._removalsHead = null;
}
}
// Add the record or a given key to the list of changes only when the value has actually changed
private _maybeAddToChanges(record: KeyValueChangeRecord_<K, V>, newValue: any): void {
if (!looseIdentical(newValue, record.currentValue)) {
record.previousValue = record.currentValue;
@ -190,52 +238,11 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
}
}
private _isInRemovals(record: KeyValueChangeRecord_<K, V>) {
return record === this._removalsHead || record._nextRemoved !== null ||
record._prevRemoved !== null;
}
private _addToRemovals(record: KeyValueChangeRecord_<K, V>) {
if (this._removalsHead === null) {
this._removalsHead = this._removalsTail = record;
} else {
this._removalsTail._nextRemoved = record;
record._prevRemoved = this._removalsTail;
this._removalsTail = record;
}
}
private _removeFromSeq(prev: KeyValueChangeRecord_<K, V>, record: KeyValueChangeRecord_<K, V>) {
const next = record._next;
if (prev === null) {
this._mapHead = next;
} else {
prev._next = next;
}
record._next = null;
}
private _removeFromRemovals(record: KeyValueChangeRecord_<K, V>) {
const prev = record._prevRemoved;
const next = record._nextRemoved;
if (prev === null) {
this._removalsHead = next;
} else {
prev._nextRemoved = next;
}
if (next === null) {
this._removalsTail = prev;
} else {
next._prevRemoved = prev;
}
record._prevRemoved = record._nextRemoved = null;
}
private _addToAdditions(record: KeyValueChangeRecord_<K, V>) {
if (this._additionsHead === null) {
this._additionsHead = this._additionsTail = record;
} else {
this._additionsTail._nextAdded = record;
this._additionsTail !._nextAdded = record;
this._additionsTail = record;
}
}
@ -244,34 +251,23 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
if (this._changesHead === null) {
this._changesHead = this._changesTail = record;
} else {
this._changesTail._nextChanged = record;
this._changesTail !._nextChanged = record;
this._changesTail = record;
}
}
toString(): string {
const items: any[] = [];
const previous: any[] = [];
const changes: any[] = [];
const additions: any[] = [];
const removals: any[] = [];
let record: KeyValueChangeRecord_<K, V>;
const items: string[] = [];
const previous: string[] = [];
const changes: string[] = [];
const additions: string[] = [];
const removals: string[] = [];
for (record = this._mapHead; record !== null; record = record._next) {
items.push(stringify(record));
}
for (record = this._previousMapHead; record !== null; record = record._nextPrevious) {
previous.push(stringify(record));
}
for (record = this._changesHead; record !== null; record = record._nextChanged) {
changes.push(stringify(record));
}
for (record = this._additionsHead; record !== null; record = record._nextAdded) {
additions.push(stringify(record));
}
for (record = this._removalsHead; record !== null; record = record._nextRemoved) {
removals.push(stringify(record));
}
this.forEachItem(r => items.push(stringify(r)));
this.forEachPreviousItem(r => previous.push(stringify(r)));
this.forEachChangedItem(r => changes.push(stringify(r)));
this.forEachAddedItem(r => additions.push(stringify(r)));
this.forEachRemovedItem(r => removals.push(stringify(r)));
return 'map: ' + items.join(', ') + '\n' +
'previous: ' + previous.join(', ') + '\n' +
@ -295,21 +291,21 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal
* @stable
*/
class KeyValueChangeRecord_<K, V> implements KeyValueChangeRecord<K, V> {
previousValue: V = null;
currentValue: V = null;
previousValue: V|null = null;
currentValue: V|null = null;
/** @internal */
_nextPrevious: KeyValueChangeRecord_<K, V> = null;
_nextPrevious: KeyValueChangeRecord_<K, V>|null = null;
/** @internal */
_next: KeyValueChangeRecord_<K, V> = null;
_next: KeyValueChangeRecord_<K, V>|null = null;
/** @internal */
_nextAdded: KeyValueChangeRecord_<K, V> = null;
_prev: KeyValueChangeRecord_<K, V>|null = null;
/** @internal */
_nextRemoved: KeyValueChangeRecord_<K, V> = null;
_nextAdded: KeyValueChangeRecord_<K, V>|null = null;
/** @internal */
_prevRemoved: KeyValueChangeRecord_<K, V> = null;
_nextRemoved: KeyValueChangeRecord_<K, V>|null = null;
/** @internal */
_nextChanged: KeyValueChangeRecord_<K, V> = null;
_nextChanged: KeyValueChangeRecord_<K, V>|null = null;
constructor(public key: K) {}

View File

@ -30,7 +30,7 @@ export interface IterableDiffer<V> {
* @returns an object describing the difference. The return value is only valid until the next
* `diff()` invocation.
*/
diff(object: NgIterable<V>): IterableChanges<V>;
diff(object: NgIterable<V>): IterableChanges<V>|null;
}
/**
@ -92,20 +92,16 @@ export interface IterableChanges<V> {
*/
export interface IterableChangeRecord<V> {
/** Current index of the item in `Iterable` or null if removed. */
// TODO(TS2.1): make readonly once we move to TS v2.1
/* readonly */ currentIndex: number;
readonly currentIndex: number|null;
/** Previous index of the item in `Iterable` or null if added. */
// TODO(TS2.1): make readonly once we move to TS v2.1
/* readonly */ previousIndex: number;
readonly previousIndex: number|null;
/** The item. */
// TODO(TS2.1): make readonly once we move to TS v2.1
/* readonly */ item: V;
readonly item: V;
/** Track by identity as computed by the `trackByFn`. */
// TODO(TS2.1): make readonly once we move to TS v2.1
/* readonly */ trackById: any;
readonly trackById: any;
}
/**

View File

@ -82,17 +82,17 @@ export interface KeyValueChangeRecord<K, V> {
/**
* Current key in the Map.
*/
/* readonly */ key: K;
readonly key: K;
/**
* Current value for the key or `undefined` if removed.
* Current value for the key or `null` if removed.
*/
/* readonly */ currentValue: V;
readonly currentValue: V|null;
/**
* Previous value for the key or `undefined` if added.
* Previous value for the key or `null` if added.
*/
/* readonly */ previousValue: V;
readonly previousValue: V|null;
}
/**

View File

@ -25,5 +25,5 @@ export {GetterFn as ɵGetterFn, MethodFn as ɵMethodFn, SetterFn as ɵSetterFn}
export {DirectRenderer as ɵDirectRenderer, RenderDebugInfo as ɵRenderDebugInfo} from './render/api';
export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util';
export {makeDecorator as ɵmakeDecorator} from './util/decorators';
export {isObservable as ɵisObservable, isPromise as ɵisPromise, merge as ɵmerge} from './util/lang';
export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang';
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider';

View File

@ -17,9 +17,9 @@ export class EventListener { constructor(public name: string, public callback: F
export class DebugNode {
nativeNode: any;
listeners: EventListener[];
parent: DebugElement;
parent: DebugElement|null;
constructor(nativeNode: any, parent: DebugNode, private _debugContext: DebugContext) {
constructor(nativeNode: any, parent: DebugNode|null, private _debugContext: DebugContext) {
this.nativeNode = nativeNode;
if (parent && parent instanceof DebugElement) {
parent.addChild(this);
@ -29,19 +29,15 @@ export class DebugNode {
this.listeners = [];
}
get injector(): Injector { return this._debugContext ? this._debugContext.injector : null; }
get injector(): Injector { return this._debugContext.injector; }
get componentInstance(): any { return this._debugContext ? this._debugContext.component : null; }
get componentInstance(): any { return this._debugContext.component; }
get context(): any { return this._debugContext ? this._debugContext.context : null; }
get context(): any { return this._debugContext.context; }
get references(): {[key: string]: any} {
return this._debugContext ? this._debugContext.references : null;
}
get references(): {[key: string]: any} { return this._debugContext.references; }
get providerTokens(): any[] {
return this._debugContext ? this._debugContext.providerTokens : null;
}
get providerTokens(): any[] { return this._debugContext.providerTokens; }
/**
* @deprecated since v4
@ -55,9 +51,9 @@ export class DebugNode {
export class DebugElement extends DebugNode {
name: string;
properties: {[key: string]: any};
attributes: {[key: string]: string};
attributes: {[key: string]: string | null};
classes: {[key: string]: boolean};
styles: {[key: string]: string};
styles: {[key: string]: string | null};
childNodes: DebugNode[];
nativeElement: any;
@ -181,8 +177,8 @@ const _nativeNodeToDebugNode = new Map<any, DebugNode>();
/**
* @experimental
*/
export function getDebugNode(nativeNode: any): DebugNode {
return _nativeNodeToDebugNode.get(nativeNode);
export function getDebugNode(nativeNode: any): DebugNode|null {
return _nativeNodeToDebugNode.get(nativeNode) || null;
}
export function getAllDebugNodes(): DebugNode[] {
@ -203,4 +199,4 @@ export function removeDebugNodeFromIndex(node: DebugNode) {
*
* @experimental All debugging apis are currently experimental.
*/
export interface Predicate<T> { (value: T, index?: number, array?: T[]): boolean; }
export interface Predicate<T> { (value: T): boolean; }

View File

@ -42,8 +42,8 @@ export class OpaqueToken {
* runtime representation) such as when injecting an interface, callable type, array or
* parametrized type.
*
* `InjectionToken` is parametrize on `T` which is the type of object which will be returned by the
* `Injector`. This provides additional level of type safety.
* `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
* the `Injector`. This provides additional level of type safety.
*
* ```
* interface MyInterface {...}
@ -53,7 +53,7 @@ export class OpaqueToken {
*
* ### Example
*
* {@example core/di/ts/injector_spec.ts region='Injector'}
* {@example core/di/ts/injector_spec.ts region='InjectionToken'}
*
* @stable
*/

View File

@ -56,7 +56,7 @@ export abstract class Injector {
*/
abstract get<T>(token: Type<T>|InjectionToken<T>, notFoundValue?: T): T;
/**
* @deprecated from v4.0.0 use Type<T> or InjectToken<T>
* @deprecated from v4.0.0 use Type<T> or InjectionToken<T>
* @suppress {duplicate}
*/
abstract get(token: any, notFoundValue?: any): any;

View File

@ -115,7 +115,7 @@ export abstract class ReflectiveInjector implements Injector {
* because it needs to resolve the passed-in providers first.
* See {@link Injector#resolve} and {@link Injector#fromResolvedProviders}.
*/
static resolveAndCreate(providers: Provider[], parent: Injector = null): ReflectiveInjector {
static resolveAndCreate(providers: Provider[], parent?: Injector): ReflectiveInjector {
const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent);
}
@ -143,7 +143,7 @@ export abstract class ReflectiveInjector implements Injector {
* ```
* @experimental
*/
static fromResolvedProviders(providers: ResolvedReflectiveProvider[], parent: Injector = null):
static fromResolvedProviders(providers: ResolvedReflectiveProvider[], parent?: Injector):
ReflectiveInjector {
return new ReflectiveInjector_(providers, parent);
}
@ -163,7 +163,7 @@ export abstract class ReflectiveInjector implements Injector {
* expect(child.parent).toBe(parent);
* ```
*/
abstract get parent(): Injector;
abstract get parent(): Injector|null;
/**
* Resolves an array of providers and creates a child injector from those providers.
@ -282,16 +282,16 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
/** @internal */
public _providers: ResolvedReflectiveProvider[];
/** @internal */
public _parent: Injector;
public _parent: Injector|null;
keyIds: number[];
objs: any[];
/**
* Private
*/
constructor(_providers: ResolvedReflectiveProvider[], _parent: Injector = null) {
constructor(_providers: ResolvedReflectiveProvider[], _parent?: Injector) {
this._providers = _providers;
this._parent = _parent;
this._parent = _parent || null;
const len = _providers.length;
@ -308,7 +308,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
return this._getByKey(ReflectiveKey.get(token), null, notFoundValue);
}
get parent(): Injector { return this._parent; }
get parent(): Injector|null { return this._parent; }
resolveAndCreateChild(providers: Provider[]): ReflectiveInjector {
const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
@ -388,7 +388,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND);
}
private _getByKey(key: ReflectiveKey, visibility: Self|SkipSelf, notFoundValue: any): any {
private _getByKey(key: ReflectiveKey, visibility: Self|SkipSelf|null, notFoundValue: any): any {
if (key === INJECTOR_KEY) {
return this;
}
@ -431,8 +431,8 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
}
/** @internal */
_getByKeyDefault(key: ReflectiveKey, notFoundValue: any, visibility: Self|SkipSelf): any {
let inj: Injector;
_getByKeyDefault(key: ReflectiveKey, notFoundValue: any, visibility: Self|SkipSelf|null): any {
let inj: Injector|null;
if (visibility instanceof SkipSelf) {
inj = this._parent;

View File

@ -64,7 +64,7 @@ export class KeyRegistry {
if (token instanceof ReflectiveKey) return token;
if (this._allKeys.has(token)) {
return this._allKeys.get(token);
return this._allKeys.get(token) !;
}
const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys);

View File

@ -26,7 +26,7 @@ interface NormalizedProvider extends TypeProvider, ValueProvider, ClassProvider,
*/
export class ReflectiveDependency {
constructor(
public key: ReflectiveKey, public optional: boolean, public visibility: Self|SkipSelf) {}
public key: ReflectiveKey, public optional: boolean, public visibility: Self|SkipSelf|null) {}
static fromKey(key: ReflectiveKey): ReflectiveDependency {
return new ReflectiveDependency(key, false, null);
@ -128,7 +128,8 @@ function resolveReflectiveFactory(provider: NormalizedProvider): ResolvedReflect
*/
function resolveReflectiveProvider(provider: NormalizedProvider): ResolvedReflectiveProvider {
return new ResolvedReflectiveProvider_(
ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)], provider.multi);
ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)],
provider.multi || false);
}
/**
@ -198,7 +199,7 @@ function _normalizeProviders(providers: Provider[], res: Provider[]): Provider[]
}
export function constructDependencies(
typeOrFunc: any, dependencies: any[]): ReflectiveDependency[] {
typeOrFunc: any, dependencies?: any[]): ReflectiveDependency[] {
if (!dependencies) {
return _dependenciesFor(typeOrFunc);
} else {
@ -230,7 +231,7 @@ function _extractToken(
}
}
let visibility: Self|SkipSelf = null;
let visibility: Self|SkipSelf|null = null;
for (let i = 0; i < metadata.length; ++i) {
const paramMetadata = metadata[i];
@ -261,6 +262,6 @@ function _extractToken(
}
function _createDependency(
token: any, optional: boolean, visibility: Self | SkipSelf): ReflectiveDependency {
token: any, optional: boolean, visibility: Self | SkipSelf | null): ReflectiveDependency {
return new ReflectiveDependency(ReflectiveKey.get(token), optional, visibility);
}

View File

@ -56,7 +56,7 @@ export class CodegenComponentFactoryResolver implements ComponentFactoryResolver
resolveComponentFactory<T>(component: {new (...args: any[]): T}): ComponentFactory<T> {
let factory = this._factories.get(component) || this._parent.resolveComponentFactory(component);
return factory ? new ComponentFactoryBoundToModule(factory, this._ngModule) : null;
return new ComponentFactoryBoundToModule(factory, this._ngModule);
}
}

View File

@ -60,7 +60,7 @@ export class NgModuleFactory<T> {
get moduleType(): Type<T> { return this._moduleType; }
create(parentInjector: Injector): NgModuleRef<T> {
create(parentInjector: Injector|null): NgModuleRef<T> {
const instance = new this._injectorClass(parentInjector || Injector.NULL);
instance.create();
return instance;

View File

@ -63,7 +63,9 @@ export class QueryList<T>/* implements Iterable<T> */ {
* See
* [Array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)
*/
find(fn: (item: T, index: number, array: T[]) => boolean): T { return this._results.find(fn); }
find(fn: (item: T, index: number, array: T[]) => boolean): T|undefined {
return this._results.find(fn);
}
/**
* See

View File

@ -51,7 +51,7 @@ export abstract class ViewContainerRef {
/**
* Returns the {@link ViewRef} for the View located in this container at the specified index.
*/
abstract get(index: number): ViewRef;
abstract get(index: number): ViewRef|null;
/**
* Returns the number of Views currently attached to this container.
@ -120,5 +120,5 @@ export abstract class ViewContainerRef {
*
* If the `index` param is omitted, the last {@link ViewRef} is detached.
*/
abstract detach(index?: number): ViewRef;
abstract detach(index?: number): ViewRef|null;
}

View File

@ -639,7 +639,7 @@ export interface Component extends Directive {
* ### DSL Animation Functions
*
* Please visit each of the animation DSL functions listed below to gain a better understanding
* of how and why they are used for crafting animations in Angular2:
* of how and why they are used for crafting animations in Angular:
*
* - {@link trigger trigger()}
* - {@link state state()}

View File

@ -62,19 +62,19 @@ export enum ViewEncapsulation {
*/
export class ViewMetadata {
/** {@link Component.templateUrl} */
templateUrl: string;
templateUrl: string|undefined;
/** {@link Component.template} */
template: string;
template: string|undefined;
/** {@link Component.stylesUrl} */
styleUrls: string[];
styleUrls: string[]|undefined;
/** {@link Component.styles} */
styles: string[];
styles: string[]|undefined;
/** {@link Component.encapsulation} */
encapsulation: ViewEncapsulation;
encapsulation: ViewEncapsulation|undefined;
/** {@link Component.animation} */
animations: any[];
animations: any[]|undefined;
/** {@link Component.interpolation} */
interpolation: [string, string];
interpolation: [string, string]|undefined;
constructor(
{templateUrl, template, encapsulation, styles, styleUrls, animations, interpolation}: {

View File

@ -53,7 +53,9 @@ export function createScope(signature: string, flags: any = null): any {
return events.createScope(signature, flags);
}
export function leave<T>(scope: Scope, returnValue?: T): T {
export function leave<T>(scope: Scope): void;
export function leave<T>(scope: Scope, returnValue?: T): T;
export function leave<T>(scope: Scope, returnValue?: any): any {
trace.leaveScope(scope, returnValue);
return returnValue;
}

View File

@ -21,6 +21,6 @@ export interface PlatformReflectionCapabilities {
method(name: string): MethodFn;
importUri(type: Type<any>): string;
resourceUri(type: Type<any>): string;
resolveIdentifier(name: string, moduleUrl: string, members: string[], runtime: any): any;
resolveIdentifier(name: string, moduleUrl: string, members: string[]|null, runtime: any): any;
resolveEnum(enumIdentifier: any, name: string): any;
}

View File

@ -14,8 +14,7 @@ import {GetterFn, MethodFn, SetterFn} from './types';
/**
* Attention: This regex has to hold even if the code is minified!
*/
export const DELEGATE_CTOR =
/^function\s+\S+\(\)\s*{\s*("use strict";)?\s*(return\s+)?(\S+\s+!==\s+null\s+&&\s+)?\S+\.apply\(this,\s*arguments\)/;
export const DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*arguments\)/;
export class ReflectionCapabilities implements PlatformReflectionCapabilities {
private _reflect: any;
@ -54,7 +53,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
return result;
}
private _ownParameters(type: Type<any>, parentCtor: any): any[][] {
private _ownParameters(type: Type<any>, parentCtor: any): any[][]|null {
// If we have no decorators, we only have function.length as metadata.
// In that case, to detect whether a child class declared an own constructor or not,
// we need to look inside of that constructor to check whether it is
@ -115,7 +114,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
return parameters || [];
}
private _ownAnnotations(typeOrFunc: Type<any>, parentCtor: any): any[] {
private _ownAnnotations(typeOrFunc: Type<any>, parentCtor: any): any[]|null {
// Prefer the direct API.
if ((<any>typeOrFunc).annotations && (<any>typeOrFunc).annotations !== parentCtor.annotations) {
let annotations = (<any>typeOrFunc).annotations;
@ -134,6 +133,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
if (this._reflect && this._reflect.getOwnMetadata) {
return this._reflect.getOwnMetadata('annotations', typeOrFunc);
}
return null;
}
annotations(typeOrFunc: Type<any>): any[] {
@ -146,7 +146,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
return parentAnnotations.concat(ownAnnotations);
}
private _ownPropMetadata(typeOrFunc: any, parentCtor: any): {[key: string]: any[]} {
private _ownPropMetadata(typeOrFunc: any, parentCtor: any): {[key: string]: any[]}|null {
// Prefer the direct API.
if ((<any>typeOrFunc).propMetadata &&
(<any>typeOrFunc).propMetadata !== parentCtor.propMetadata) {
@ -172,6 +172,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
if (this._reflect && this._reflect.getOwnMetadata) {
return this._reflect.getOwnMetadata('propMetadata', typeOrFunc);
}
return null;
}
propMetadata(typeOrFunc: any): {[key: string]: any[]} {

View File

@ -51,7 +51,7 @@ export class Reflector extends ReflectorReader {
resourceUri(type: any): string { return this.reflectionCapabilities.resourceUri(type); }
resolveIdentifier(name: string, moduleUrl: string, members: string[], runtime: any): any {
resolveIdentifier(name: string, moduleUrl: string, members: string[]|null, runtime: any): any {
return this.reflectionCapabilities.resolveIdentifier(name, moduleUrl, members, runtime);
}

View File

@ -14,7 +14,7 @@ export abstract class ReflectorReader {
abstract parameters(typeOrFunc: /*Type*/ any): any[][];
abstract annotations(typeOrFunc: /*Type*/ any): any[];
abstract propMetadata(typeOrFunc: /*Type*/ any): {[key: string]: any[]};
abstract importUri(typeOrFunc: /*Type*/ any): string;
abstract importUri(typeOrFunc: /*Type*/ any): string|null;
abstract resourceUri(typeOrFunc: /*Type*/ any): string;
abstract resolveIdentifier(name: string, moduleUrl: string, members: string[], runtime: any): any;
abstract resolveEnum(identifier: any, name: string): any;

View File

@ -126,7 +126,7 @@ export interface RendererType2 {
* @experimental
*/
export abstract class RendererFactory2 {
abstract createRenderer(hostElement: any, type: RendererType2): Renderer2;
abstract createRenderer(hostElement: any, type: RendererType2|null): Renderer2;
}
/**
@ -148,7 +148,7 @@ export abstract class Renderer2 {
abstract get data(): {[key: string]: any};
abstract destroy(): void;
abstract createElement(name: string, namespace?: string): any;
abstract createElement(name: string, namespace?: string|null): any;
abstract createComment(value: string): any;
abstract createText(value: string): any;
/**
@ -156,7 +156,7 @@ export abstract class Renderer2 {
* in which case the view engine won't call it.
* This is used as a performance optimization for production mode.
*/
destroyNode: (node: any) => void | null;
destroyNode: ((node: any) => void)|null;
abstract appendChild(parent: any, newChild: any): void;
abstract insertBefore(parent: any, newChild: any, refChild: any): void;
abstract removeChild(parent: any, oldChild: any): void;
@ -173,8 +173,8 @@ export abstract class Renderer2 {
* the caller can't rely on checking whether this is null or not.
*/
abstract nextSibling(node: any): any;
abstract setAttribute(el: any, name: string, value: string, namespace?: string): void;
abstract removeAttribute(el: any, name: string, namespace?: string): void;
abstract setAttribute(el: any, name: string, value: string, namespace?: string|null): void;
abstract removeAttribute(el: any, name: string, namespace?: string|null): void;
abstract addClass(el: any, name: string): void;
abstract removeClass(el: any, name: string): void;
abstract setStyle(el: any, style: string, value: any, flags?: RendererStyleFlags2): void;

View File

@ -0,0 +1,23 @@
/** @externs */
/** @record @struct */
function PublicTestability() {}
/**
* @return {?}
*/
PublicTestability.prototype.isStable = function() {};
/**
* @param {?} callback
* @return {?}
*/
PublicTestability.prototype.whenStable = function(callback) {};
/**
* @param {?} using
* @param {?} provider
* @param {?} exactMatch
* @return {?}
*/
PublicTestability.prototype.findProviders = function(using, provider, exactMatch) {};

View File

@ -92,7 +92,7 @@ export class Testability implements PublicTestability {
// Schedules the call backs in a new frame so that it is always async.
scheduleMicroTask(() => {
while (this._callbacks.length !== 0) {
(this._callbacks.pop())(this._didWork);
(this._callbacks.pop() !)(this._didWork);
}
this._didWork = false;
});
@ -136,13 +136,13 @@ export class TestabilityRegistry {
this._applications.set(token, testability);
}
getTestability(elem: any): Testability { return this._applications.get(elem); }
getTestability(elem: any): Testability|null { return this._applications.get(elem) || null; }
getAllTestabilities(): Testability[] { return Array.from(this._applications.values()); }
getAllRootElements(): any[] { return Array.from(this._applications.keys()); }
findTestabilityInTree(elem: Node, findInAncestors: boolean = true): Testability {
findTestabilityInTree(elem: Node, findInAncestors: boolean = true): Testability|null {
return _testabilityGetter.findTestabilityInTree(this, elem, findInAncestors);
}
}
@ -157,13 +157,13 @@ export class TestabilityRegistry {
export interface GetTestability {
addToWindow(registry: TestabilityRegistry): void;
findTestabilityInTree(registry: TestabilityRegistry, elem: any, findInAncestors: boolean):
Testability;
Testability|null;
}
class _NoopGetTestability implements GetTestability {
addToWindow(registry: TestabilityRegistry): void {}
findTestabilityInTree(registry: TestabilityRegistry, elem: any, findInAncestors: boolean):
Testability {
Testability|null {
return null;
}
}

View File

@ -96,7 +96,7 @@ function extractAnnotation(annotation: any): any {
return annotation;
}
function applyParams(fnOrArray: (Function | any[]), key: string): Function {
function applyParams(fnOrArray: Function | any[] | undefined, key: string): Function {
if (fnOrArray === Object || fnOrArray === String || fnOrArray === Function ||
fnOrArray === Number || fnOrArray === Array) {
throw new Error(`Can not use native ${stringify(fnOrArray)} as constructor`);
@ -107,7 +107,7 @@ function applyParams(fnOrArray: (Function | any[]), key: string): Function {
}
if (Array.isArray(fnOrArray)) {
const annotations: any[] = fnOrArray;
const annotations: any[] = fnOrArray as any[];
const annoLength = annotations.length - 1;
const fn: Function = fnOrArray[annoLength];
if (typeof fn !== 'function') {
@ -263,7 +263,7 @@ export function Class(clsDef: ClassDefinition): Type<any> {
*/
export function makeDecorator(
name: string, props: {[name: string]: any}, parentClass?: any,
chainFn: (fn: Function) => void = null): (...args: any[]) => (cls: any) => any {
chainFn?: (fn: Function) => void): (...args: any[]) => (cls: any) => any {
const metaCtor = makeMetadataCtor([props]);
function DecoratorFactory(objOrType: any): (cls: any) => any {
@ -332,7 +332,7 @@ export function makeParamDecorator(
return ParamDecorator;
function ParamDecorator(cls: any, unusedKey: any, index: number): any {
const parameters: any[][] = Reflect.getOwnMetadata('parameters', cls) || [];
const parameters: (any[] | null)[] = Reflect.getOwnMetadata('parameters', cls) || [];
// there might be gaps if some in between parameters do not have annotations.
// we pad with nulls.
@ -341,7 +341,7 @@ export function makeParamDecorator(
}
parameters[index] = parameters[index] || [];
parameters[index].push(annotationInstance);
parameters[index] !.push(annotationInstance);
Reflect.defineMetadata('parameters', parameters, cls);
return cls;

View File

@ -24,18 +24,3 @@ export function isObservable(obj: any | Observable<any>): obj is Observable<any>
// TODO use Symbol.observable when https://github.com/ReactiveX/rxjs/issues/2415 will be resolved
return !!obj && typeof obj.subscribe === 'function';
}
// TODO(misko): replace with Object.assign once we require ES6.
export function merge<V>(m1: {[key: string]: V}, m2: {[key: string]: V}): {[key: string]: V} {
const m: {[key: string]: V} = {};
for (const k of Object.keys(m1)) {
m[k] = m1[k];
}
for (const k of Object.keys(m2)) {
m[k] = m2[k];
}
return m;
}

View File

@ -16,20 +16,17 @@ export function anchorDef(
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][],
ngContentIndex: number, childCount: number, handleEvent?: ElementHandleEventFn,
templateFactory?: ViewDefinitionFactory): NodeDef {
if (!handleEvent) {
handleEvent = NOOP;
}
flags |= NodeFlags.TypeElement;
const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl);
const template = templateFactory ? resolveViewDefinition(templateFactory) : null;
return {
// will bet set by the view definition
index: undefined,
parent: undefined,
renderParent: undefined,
bindingIndex: undefined,
outputIndex: undefined,
index: -1,
parent: null,
renderParent: null,
bindingIndex: -1,
outputIndex: -1,
// regular values
flags,
childFlags: 0,
@ -39,19 +36,20 @@ export function anchorDef(
bindingFlags: 0,
outputs: [],
element: {
ns: undefined,
name: undefined,
attrs: undefined, template,
componentProvider: undefined,
componentView: undefined,
componentRendererType: undefined,
publicProviders: undefined,
allProviders: undefined, handleEvent
ns: null,
name: null,
attrs: null, template,
componentProvider: null,
componentView: null,
componentRendererType: null,
publicProviders: null,
allProviders: null,
handleEvent: handleEvent || NOOP
},
provider: undefined,
text: undefined,
query: undefined,
ngContent: undefined
provider: null,
text: null,
query: null,
ngContent: null
};
}
@ -61,13 +59,13 @@ export function elementDef(
fixedAttrs: [string, string][] = [],
bindings?: [BindingFlags, string, string | SecurityContext][], outputs?: ([string, string])[],
handleEvent?: ElementHandleEventFn, componentView?: ViewDefinitionFactory,
componentRendererType?: RendererType2): NodeDef {
componentRendererType?: RendererType2 | null): NodeDef {
if (!handleEvent) {
handleEvent = NOOP;
}
const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl);
let ns: string;
let name: string;
let ns: string = null !;
let name: string = null !;
if (namespaceAndName) {
[ns, name] = splitNamespace(namespaceAndName);
}
@ -77,8 +75,8 @@ export function elementDef(
const [bindingFlags, namespaceAndName, suffixOrSecurityContext] = bindings[i];
const [ns, name] = splitNamespace(namespaceAndName);
let securityContext: SecurityContext;
let suffix: string;
let securityContext: SecurityContext = undefined !;
let suffix: string = undefined !;
switch (bindingFlags & BindingFlags.Types) {
case BindingFlags.TypeElementStyle:
suffix = <string>suffixOrSecurityContext;
@ -98,7 +96,7 @@ export function elementDef(
outputDefs[i] = {
type: OutputType.ElementOutput,
target: <any>target, eventName,
propName: undefined
propName: null
};
}
fixedAttrs = fixedAttrs || [];
@ -113,11 +111,11 @@ export function elementDef(
flags |= NodeFlags.TypeElement;
return {
// will bet set by the view definition
index: undefined,
parent: undefined,
renderParent: undefined,
bindingIndex: undefined,
outputIndex: undefined,
index: -1,
parent: null,
renderParent: null,
bindingIndex: -1,
outputIndex: -1,
// regular values
flags,
childFlags: 0,
@ -130,21 +128,24 @@ export function elementDef(
ns,
name,
attrs,
template: undefined,
template: null,
// will bet set by the view definition
componentProvider: undefined, componentView, componentRendererType,
publicProviders: undefined,
allProviders: undefined, handleEvent,
componentProvider: null,
componentView: componentView || null,
componentRendererType: componentRendererType,
publicProviders: null,
allProviders: null,
handleEvent: handleEvent || NOOP,
},
provider: undefined,
text: undefined,
query: undefined,
ngContent: undefined
provider: null,
text: null,
query: null,
ngContent: null
};
}
export function createElement(view: ViewData, renderHost: any, def: NodeDef): ElementData {
const elDef = def.element;
const elDef = def.element !;
const rootSelectorOrNode = view.root.selectorOrNode;
const renderer = view.renderer;
let el: any;
@ -175,7 +176,7 @@ export function listenToElementOutputs(view: ViewData, compView: ViewData, def:
const output = def.outputs[i];
const handleEventClosure = renderEventHandlerClosure(
view, def.index, elementEventFullName(output.target, output.eventName));
let listenTarget = output.target;
let listenTarget: 'window'|'document'|'body'|'component'|null = output.target;
let listenerView = view;
if (output.target === 'component') {
listenTarget = null;
@ -183,7 +184,7 @@ export function listenToElementOutputs(view: ViewData, compView: ViewData, def:
}
const disposable =
<any>listenerView.renderer.listen(listenTarget || el, output.eventName, handleEventClosure);
view.disposables[def.outputIndex + i] = disposable;
view.disposables ![def.outputIndex + i] = disposable;
}
}
@ -225,7 +226,7 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
const binding = def.bindings[bindingIdx];
const elData = asElementData(view, def.index);
const renderNode = elData.renderElement;
const name = binding.name;
const name = binding.name !;
switch (binding.flags & BindingFlags.Types) {
case BindingFlags.TypeElementAttribute:
setElementAttribute(view, binding, renderNode, binding.ns, name, value);
@ -248,7 +249,8 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
}
function setElementAttribute(
view: ViewData, binding: BindingDef, renderNode: any, ns: string, name: string, value: any) {
view: ViewData, binding: BindingDef, renderNode: any, ns: string | null, name: string,
value: any) {
const securityContext = binding.securityContext;
let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value;
renderValue = renderValue != null ? renderValue.toString() : null;
@ -271,7 +273,7 @@ function setElementClass(view: ViewData, renderNode: any, name: string, value: b
function setElementStyle(
view: ViewData, binding: BindingDef, renderNode: any, name: string, value: any) {
let renderValue = view.root.sanitizer.sanitize(SecurityContext.STYLE, value);
let renderValue: string|null = view.root.sanitizer.sanitize(SecurityContext.STYLE, value);
if (renderValue != null) {
renderValue = renderValue.toString();
const unit = binding.suffix;

View File

@ -12,11 +12,11 @@ import {RenderNodeAction, getParentRenderElement, visitProjectedRenderNodes} fro
export function ngContentDef(ngContentIndex: number, index: number): NodeDef {
return {
// will bet set by the view definition
index: undefined,
parent: undefined,
renderParent: undefined,
bindingIndex: undefined,
outputIndex: undefined,
index: -1,
parent: null,
renderParent: null,
bindingIndex: -1,
outputIndex: -1,
// regular values
flags: NodeFlags.TypeNgContent,
childFlags: 0,
@ -29,10 +29,10 @@ export function ngContentDef(ngContentIndex: number, index: number): NodeDef {
bindings: [],
bindingFlags: 0,
outputs: [],
element: undefined,
provider: undefined,
text: undefined,
query: undefined,
element: null,
provider: null,
text: null,
query: null,
ngContent: {index}
};
}
@ -43,7 +43,7 @@ export function appendNgContent(view: ViewData, renderHost: any, def: NodeDef) {
// Nothing to do if there is no parent element.
return;
}
const ngContentIndex = def.ngContent.index;
const ngContentIndex = def.ngContent !.index;
visitProjectedRenderNodes(
view, ngContentIndex, RenderNodeAction.AppendChild, parentEl, undefined, undefined);
view, ngContentIndex, RenderNodeAction.AppendChild, parentEl, null, undefined);
}

View File

@ -38,9 +38,9 @@ export function directiveDef(
bindings[bindingIndex] = {
flags: BindingFlags.TypeProperty,
name: prop, nonMinifiedName,
ns: undefined,
securityContext: undefined,
suffix: undefined
ns: null,
securityContext: null,
suffix: null
};
}
}
@ -67,9 +67,9 @@ export function providerDef(
}
export function _def(
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][], childCount: number,
token: any, value: any, deps: ([DepFlags, any] | any)[], bindings?: BindingDef[],
outputs?: OutputDef[]): NodeDef {
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][] | null,
childCount: number, token: any, value: any, deps: ([DepFlags, any] | any)[],
bindings?: BindingDef[], outputs?: OutputDef[]): NodeDef {
const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl);
if (!outputs) {
outputs = [];
@ -92,23 +92,23 @@ export function _def(
return {
// will bet set by the view definition
index: undefined,
parent: undefined,
renderParent: undefined,
bindingIndex: undefined,
outputIndex: undefined,
index: -1,
parent: null,
renderParent: null,
bindingIndex: -1,
outputIndex: -1,
// regular values
flags,
childFlags: 0,
directChildFlags: 0,
childMatchedQueries: 0, matchedQueries, matchedQueryIds, references,
ngContentIndex: undefined, childCount, bindings,
ngContentIndex: -1, childCount, bindings,
bindingFlags: calcBindingFlags(bindings), outputs,
element: undefined,
element: null,
provider: {token, tokenKey: tokenKey(token), value, deps: depDefs},
text: undefined,
query: undefined,
ngContent: undefined
text: null,
query: null,
ngContent: null
};
}
@ -126,22 +126,22 @@ export function createPipeInstance(view: ViewData, def: NodeDef): any {
const allowPrivateServices = true;
// pipes are always eager and classes!
return createClass(
compView.parent, viewParentEl(compView), allowPrivateServices, def.provider.value,
def.provider.deps);
compView.parent !, viewParentEl(compView) !, allowPrivateServices, def.provider !.value,
def.provider !.deps);
}
export function createDirectiveInstance(view: ViewData, def: NodeDef): any {
// components can see other private services, other directives can't.
const allowPrivateServices = (def.flags & NodeFlags.Component) > 0;
// directives are always eager and classes!
const instance =
createClass(view, def.parent, allowPrivateServices, def.provider.value, def.provider.deps);
const instance = createClass(
view, def.parent !, allowPrivateServices, def.provider !.value, def.provider !.deps);
if (def.outputs.length) {
for (let i = 0; i < def.outputs.length; i++) {
const output = def.outputs[i];
const subscription = instance[output.propName].subscribe(
eventHandlerClosure(view, def.parent.index, output.eventName));
view.disposables[def.outputIndex + i] = subscription.unsubscribe.bind(subscription);
const subscription = instance[output.propName !].subscribe(
eventHandlerClosure(view, def.parent !.index, output.eventName));
view.disposables ![def.outputIndex + i] = subscription.unsubscribe.bind(subscription);
}
}
return instance;
@ -157,48 +157,48 @@ export function checkAndUpdateDirectiveInline(
const providerData = asProviderData(view, def.index);
const directive = providerData.instance;
let changed = false;
let changes: SimpleChanges;
let changes: SimpleChanges = undefined !;
const bindLen = def.bindings.length;
if (bindLen > 0 && checkBinding(view, def, 0, v0)) {
changed = true;
changes = updateProp(view, providerData, def, 0, v0, changes);
};
}
if (bindLen > 1 && checkBinding(view, def, 1, v1)) {
changed = true;
changes = updateProp(view, providerData, def, 1, v1, changes);
};
}
if (bindLen > 2 && checkBinding(view, def, 2, v2)) {
changed = true;
changes = updateProp(view, providerData, def, 2, v2, changes);
};
}
if (bindLen > 3 && checkBinding(view, def, 3, v3)) {
changed = true;
changes = updateProp(view, providerData, def, 3, v3, changes);
};
}
if (bindLen > 4 && checkBinding(view, def, 4, v4)) {
changed = true;
changes = updateProp(view, providerData, def, 4, v4, changes);
};
}
if (bindLen > 5 && checkBinding(view, def, 5, v5)) {
changed = true;
changes = updateProp(view, providerData, def, 5, v5, changes);
};
}
if (bindLen > 6 && checkBinding(view, def, 6, v6)) {
changed = true;
changes = updateProp(view, providerData, def, 6, v6, changes);
};
}
if (bindLen > 7 && checkBinding(view, def, 7, v7)) {
changed = true;
changes = updateProp(view, providerData, def, 7, v7, changes);
};
}
if (bindLen > 8 && checkBinding(view, def, 8, v8)) {
changed = true;
changes = updateProp(view, providerData, def, 8, v8, changes);
};
}
if (bindLen > 9 && checkBinding(view, def, 9, v9)) {
changed = true;
changes = updateProp(view, providerData, def, 9, v9, changes);
};
}
if (changes) {
directive.ngOnChanges(changes);
}
@ -216,7 +216,7 @@ export function checkAndUpdateDirectiveDynamic(
const providerData = asProviderData(view, def.index);
const directive = providerData.instance;
let changed = false;
let changes: SimpleChanges;
let changes: SimpleChanges = undefined !;
for (let i = 0; i < values.length; i++) {
if (checkBinding(view, def, i, values[i])) {
changed = true;
@ -242,18 +242,18 @@ function _createProviderInstance(view: ViewData, def: NodeDef): any {
let injectable: any;
switch (def.flags & NodeFlags.Types) {
case NodeFlags.TypeClassProvider:
injectable =
createClass(view, def.parent, allowPrivateServices, providerDef.value, providerDef.deps);
injectable = createClass(
view, def.parent !, allowPrivateServices, providerDef !.value, providerDef !.deps);
break;
case NodeFlags.TypeFactoryProvider:
injectable =
callFactory(view, def.parent, allowPrivateServices, providerDef.value, providerDef.deps);
injectable = callFactory(
view, def.parent !, allowPrivateServices, providerDef !.value, providerDef !.deps);
break;
case NodeFlags.TypeUseExistingProvider:
injectable = resolveDep(view, def.parent, allowPrivateServices, providerDef.deps[0]);
injectable = resolveDep(view, def.parent !, allowPrivateServices, providerDef !.deps[0]);
break;
case NodeFlags.TypeValueProvider:
injectable = providerDef.value;
injectable = providerDef !.value;
break;
}
return injectable;
@ -345,7 +345,7 @@ export const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
export function resolveDep(
view: ViewData, elDef: NodeDef, allowPrivateServices: boolean, depDef: DepDef,
notFoundValue = Injector.THROW_IF_NOT_FOUND): any {
notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any {
if (depDef.flags & DepFlags.Value) {
return depDef.token;
}
@ -357,7 +357,7 @@ export function resolveDep(
if (elDef && (depDef.flags & DepFlags.SkipSelf)) {
allowPrivateServices = false;
elDef = elDef.parent;
elDef = elDef.parent !;
}
while (view) {
@ -376,7 +376,7 @@ export function resolveDep(
case ViewContainerRefTokenKey:
return asElementData(view, elDef.index).viewContainer;
case TemplateRefTokenKey: {
if (elDef.element.template) {
if (elDef.element !.template) {
return asElementData(view, elDef.index).template;
}
break;
@ -389,8 +389,8 @@ export function resolveDep(
return createInjector(view, elDef);
default:
const providerDef =
(allowPrivateServices ? elDef.element.allProviders :
elDef.element.publicProviders)[tokenKey];
(allowPrivateServices ? elDef.element !.allProviders :
elDef.element !.publicProviders) ![tokenKey];
if (providerDef) {
const providerData = asProviderData(view, providerDef.index);
if (providerData.instance === NOT_CREATED) {
@ -401,8 +401,8 @@ export function resolveDep(
}
}
allowPrivateServices = isComponentView(view);
elDef = viewParentEl(view);
view = view.parent;
elDef = viewParentEl(view) !;
view = view.parent !;
}
const value = startView.root.injector.get(depDef.token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR);
@ -437,13 +437,13 @@ function updateProp(
view: ViewData, providerData: ProviderData, def: NodeDef, bindingIdx: number, value: any,
changes: SimpleChanges): SimpleChanges {
if (def.flags & NodeFlags.Component) {
const compView = asElementData(view, def.parent.index).componentView;
const compView = asElementData(view, def.parent !.index).componentView;
if (compView.def.flags & ViewFlags.OnPush) {
compView.state |= ViewState.ChecksEnabled;
}
}
const binding = def.bindings[bindingIdx];
const propName = binding.name;
const propName = binding.name !;
// Note: This is still safe with Closure Compiler as
// the user passed in the property name as an object has to `providerDef`,
// so Closure Compiler will have renamed the property correctly already.
@ -455,7 +455,7 @@ function updateProp(
oldValue = oldValue.wrapped;
}
const binding = def.bindings[bindingIdx];
changes[binding.nonMinifiedName] =
changes[binding.nonMinifiedName !] =
new SimpleChange(oldValue, value, (view.state & ViewState.FirstCheck) !== 0);
}
view.oldValues[def.bindingIndex + bindingIdx] = value;

View File

@ -29,19 +29,19 @@ function _pureExpressionDef(flags: NodeFlags, propertyNames: string[]): NodeDef
bindings[i] = {
flags: BindingFlags.TypeProperty,
name: prop,
ns: undefined,
ns: null,
nonMinifiedName: prop,
securityContext: undefined,
suffix: undefined
securityContext: null,
suffix: null
};
}
return {
// will bet set by the view definition
index: undefined,
parent: undefined,
renderParent: undefined,
bindingIndex: undefined,
outputIndex: undefined,
index: -1,
parent: null,
renderParent: null,
bindingIndex: -1,
outputIndex: -1,
// regular values
flags,
childFlags: 0,
@ -50,15 +50,15 @@ function _pureExpressionDef(flags: NodeFlags, propertyNames: string[]): NodeDef
matchedQueries: {},
matchedQueryIds: 0,
references: {},
ngContentIndex: undefined,
ngContentIndex: -1,
childCount: 0, bindings,
bindingFlags: calcBindingFlags(bindings),
outputs: [],
element: undefined,
provider: undefined,
text: undefined,
query: undefined,
ngContent: undefined
element: null,
provider: null,
text: null,
query: null,
ngContent: null
};
}
@ -102,16 +102,16 @@ export function checkAndUpdatePureExpressionInline(
break;
case NodeFlags.TypePureObject:
value = {};
if (bindLen > 0) value[bindings[0].name] = v0;
if (bindLen > 1) value[bindings[1].name] = v1;
if (bindLen > 2) value[bindings[2].name] = v2;
if (bindLen > 3) value[bindings[3].name] = v3;
if (bindLen > 4) value[bindings[4].name] = v4;
if (bindLen > 5) value[bindings[5].name] = v5;
if (bindLen > 6) value[bindings[6].name] = v6;
if (bindLen > 7) value[bindings[7].name] = v7;
if (bindLen > 8) value[bindings[8].name] = v8;
if (bindLen > 9) value[bindings[9].name] = v9;
if (bindLen > 0) value[bindings[0].name !] = v0;
if (bindLen > 1) value[bindings[1].name !] = v1;
if (bindLen > 2) value[bindings[2].name !] = v2;
if (bindLen > 3) value[bindings[3].name !] = v3;
if (bindLen > 4) value[bindings[4].name !] = v4;
if (bindLen > 5) value[bindings[5].name !] = v5;
if (bindLen > 6) value[bindings[6].name !] = v6;
if (bindLen > 7) value[bindings[7].name !] = v7;
if (bindLen > 8) value[bindings[8].name !] = v8;
if (bindLen > 9) value[bindings[9].name !] = v9;
break;
case NodeFlags.TypePurePipe:
const pipe = v0;
@ -175,7 +175,7 @@ export function checkAndUpdatePureExpressionDynamic(
case NodeFlags.TypePureObject:
value = {};
for (let i = 0; i < values.length; i++) {
value[bindings[i].name] = values[i];
value[bindings[i].name !] = values[i];
}
break;
case NodeFlags.TypePurePipe:

View File

@ -22,17 +22,17 @@ export function queryDef(
return {
// will bet set by the view definition
index: undefined,
parent: undefined,
renderParent: undefined,
bindingIndex: undefined,
outputIndex: undefined,
index: -1,
parent: null,
renderParent: null,
bindingIndex: -1,
outputIndex: -1,
// regular values
flags,
childFlags: 0,
directChildFlags: 0,
childMatchedQueries: 0,
ngContentIndex: undefined,
ngContentIndex: -1,
matchedQueries: {},
matchedQueryIds: 0,
references: {},
@ -40,11 +40,11 @@ export function queryDef(
bindings: [],
bindingFlags: 0,
outputs: [],
element: undefined,
provider: undefined,
text: undefined,
element: null,
provider: null,
text: null,
query: {id, filterId: filterQueryId(id), bindings: bindingDefs},
ngContent: undefined
ngContent: null
};
}
@ -55,7 +55,7 @@ export function createQuery(): QueryList<any> {
export function dirtyParentQueries(view: ViewData) {
const queryIds = view.def.nodeMatchedQueries;
while (view.parent && isEmbeddedView(view)) {
let tplDef = view.parentNodeDef;
let tplDef = view.parentNodeDef !;
view = view.parent;
// content queries
const end = tplDef.index + tplDef.childCount;
@ -63,7 +63,7 @@ export function dirtyParentQueries(view: ViewData) {
const nodeDef = view.def.nodes[i];
if ((nodeDef.flags & NodeFlags.TypeContentQuery) &&
(nodeDef.flags & NodeFlags.DynamicQuery) &&
(nodeDef.query.filterId & queryIds) === nodeDef.query.filterId) {
(nodeDef.query !.filterId & queryIds) === nodeDef.query !.filterId) {
asQueryList(view, i).setDirty();
}
if ((nodeDef.flags & NodeFlags.TypeElement && i + nodeDef.childCount < tplDef.index) ||
@ -94,18 +94,18 @@ export function checkAndUpdateQuery(view: ViewData, nodeDef: NodeDef) {
return;
}
let directiveInstance: any;
let newValues: any[];
let newValues: any[] = undefined !;
if (nodeDef.flags & NodeFlags.TypeContentQuery) {
const elementDef = nodeDef.parent.parent;
const elementDef = nodeDef.parent !.parent !;
newValues = calcQueryValues(
view, elementDef.index, elementDef.index + elementDef.childCount, nodeDef.query, []);
directiveInstance = asProviderData(view, nodeDef.parent.index).instance;
view, elementDef.index, elementDef.index + elementDef.childCount, nodeDef.query !, []);
directiveInstance = asProviderData(view, nodeDef.parent !.index).instance;
} else if (nodeDef.flags & NodeFlags.TypeViewQuery) {
newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query, []);
newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query !, []);
directiveInstance = view.component;
}
queryList.reset(newValues);
const bindings = nodeDef.query.bindings;
const bindings = nodeDef.query !.bindings;
let notify = false;
for (let i = 0; i < bindings.length; i++) {
const binding = bindings[i];
@ -135,12 +135,13 @@ function calcQueryValues(
if (valueType != null) {
values.push(getQueryValue(view, nodeDef, valueType));
}
if (nodeDef.flags & NodeFlags.TypeElement && nodeDef.element.template &&
(nodeDef.element.template.nodeMatchedQueries & queryDef.filterId) === queryDef.filterId) {
if (nodeDef.flags & NodeFlags.TypeElement && nodeDef.element !.template &&
(nodeDef.element !.template !.nodeMatchedQueries & queryDef.filterId) ===
queryDef.filterId) {
// check embedded views that were attached at the place of their template.
const elementData = asElementData(view, i);
if (nodeDef.flags & NodeFlags.EmbeddedViews) {
const embeddedViews = elementData.viewContainer._embeddedViews;
const embeddedViews = elementData.viewContainer !._embeddedViews;
for (let k = 0; k < embeddedViews.length; k++) {
const embeddedView = embeddedViews[k];
const dvc = declaredViewContainer(embeddedView);

View File

@ -85,7 +85,7 @@ class ComponentFactory_ extends ComponentFactory<any> {
throw new Error('ngModule should be provided');
}
const viewDef = resolveViewDefinition(this.viewDefFactory);
const componentNodeIndex = viewDef.nodes[0].element.componentProvider.index;
const componentNodeIndex = viewDef.nodes[0].element !.componentProvider !.index;
const view = Services.createRootView(
injector, projectableNodes || [], rootSelectorOrNode, viewDef, ngModule, EMPTY_CONTEXT);
const component = asProviderData(view, componentNodeIndex).instance;
@ -135,7 +135,7 @@ class ViewContainerRef_ implements ViewContainerData {
let elDef = this._elDef.parent;
while (!elDef && view) {
elDef = viewParentEl(view);
view = view.parent;
view = view.parent !;
}
return view ? new Injector_(view, elDef) : new Injector_(this._view, null);
@ -144,12 +144,12 @@ class ViewContainerRef_ implements ViewContainerData {
clear(): void {
const len = this._embeddedViews.length;
for (let i = len - 1; i >= 0; i--) {
const view = detachEmbeddedView(this._data, i);
const view = detachEmbeddedView(this._data, i) !;
Services.destroyView(view);
}
}
get(index: number): ViewRef {
get(index: number): ViewRef|null {
const view = this._embeddedViews[index];
if (view) {
const ref = new ViewRef_(view);
@ -206,7 +206,7 @@ class ViewContainerRef_ implements ViewContainerData {
}
}
detach(index?: number): ViewRef {
detach(index?: number): ViewRef|null {
const view = detachEmbeddedView(this._data, index);
return view ? new ViewRef_(view) : null;
}
@ -219,8 +219,8 @@ export function createChangeDetectorRef(view: ViewData): ChangeDetectorRef {
export class ViewRef_ implements EmbeddedViewRef<any>, InternalViewRef {
/** @internal */
_view: ViewData;
private _viewContainerRef: ViewContainerRef;
private _appRef: ApplicationRef;
private _viewContainerRef: ViewContainerRef|null;
private _appRef: ApplicationRef|null;
constructor(_view: ViewData) {
this._view = _view;
@ -317,7 +317,7 @@ export function nodeValue(view: ViewData, index: number): any {
const def = view.def.nodes[index];
if (def.flags & NodeFlags.TypeElement) {
const elData = asElementData(view, def.index);
return def.element.template ? elData.template : elData.renderElement;
return def.element !.template ? elData.template : elData.renderElement;
} else if (def.flags & NodeFlags.TypeText) {
return asTextData(view, def.index).renderText;
} else if (def.flags & (NodeFlags.CatProvider | NodeFlags.TypePipe)) {
@ -387,7 +387,7 @@ class RendererAdapter implements RendererV1 {
destroyView(hostElement: Element|DocumentFragment, viewAllNodes: Node[]) {
for (let i = 0; i < viewAllNodes.length; i++) {
this.delegate.destroyNode(viewAllNodes[i]);
this.delegate.destroyNode !(viewAllNodes[i]);
}
}
@ -439,4 +439,4 @@ class RendererAdapter implements RendererV1 {
setText(renderNode: Text, text: string): void { this.delegate.setValue(renderNode, text); }
animate(): any { throw new Error('Renderer.animate is no longer supported!'); }
}
}

View File

@ -159,9 +159,9 @@ enum DebugAction {
let _currentAction: DebugAction;
let _currentView: ViewData;
let _currentNodeIndex: number;
let _currentNodeIndex: number|null;
function debugSetCurrentNode(view: ViewData, nodeIndex: number) {
function debugSetCurrentNode(view: ViewData, nodeIndex: number | null) {
_currentView = view;
_currentNodeIndex = nodeIndex;
}
@ -231,13 +231,13 @@ function debugCheckAndUpdateNode(
const binding = nodeDef.bindings[i];
const value = values[i];
if (binding.flags & BindingFlags.TypeProperty) {
bindingValues[normalizeDebugBindingName(binding.nonMinifiedName)] =
bindingValues[normalizeDebugBindingName(binding.nonMinifiedName !)] =
normalizeDebugBindingValue(value);
}
}
const elDef = nodeDef.parent;
const elDef = nodeDef.parent !;
const el = asElementData(view, elDef.index).renderElement;
if (!elDef.element.name) {
if (!elDef.element !.name) {
// a comment.
view.renderer.setValue(el, `bindings=${JSON.stringify(bindingValues, null, 2)}`);
} else {
@ -275,37 +275,37 @@ function camelCaseToDashCase(input: string): string {
function normalizeDebugBindingValue(value: any): string {
try {
// Limit the size of the value as otherwise the DOM just gets polluted.
return value ? value.toString().slice(0, 30) : value;
return value != null ? value.toString().slice(0, 30) : value;
} catch (e) {
return '[ERROR] Exception while trying to serialize the value';
}
}
function nextDirectiveWithBinding(view: ViewData, nodeIndex: number): number {
function nextDirectiveWithBinding(view: ViewData, nodeIndex: number): number|null {
for (let i = nodeIndex; i < view.def.nodes.length; i++) {
const nodeDef = view.def.nodes[i];
if (nodeDef.flags & NodeFlags.TypeDirective && nodeDef.bindings && nodeDef.bindings.length) {
return i;
}
}
return undefined;
return null;
}
function nextRenderNodeWithBinding(view: ViewData, nodeIndex: number): number {
function nextRenderNodeWithBinding(view: ViewData, nodeIndex: number): number|null {
for (let i = nodeIndex; i < view.def.nodes.length; i++) {
const nodeDef = view.def.nodes[i];
if ((nodeDef.flags & NodeFlags.CatRenderNode) && nodeDef.bindings && nodeDef.bindings.length) {
return i;
}
}
return undefined;
return null;
}
class DebugContext_ implements DebugContext {
private nodeDef: NodeDef;
private elView: ViewData;
private elDef: NodeDef;
constructor(public view: ViewData, public nodeIndex: number) {
constructor(public view: ViewData, public nodeIndex: number|null) {
if (nodeIndex == null) {
this.nodeIndex = nodeIndex = 0;
}
@ -313,12 +313,12 @@ class DebugContext_ implements DebugContext {
let elDef = this.nodeDef;
let elView = view;
while (elDef && (elDef.flags & NodeFlags.TypeElement) === 0) {
elDef = elDef.parent;
elDef = elDef.parent !;
}
if (!elDef) {
while (!elDef && elView) {
elDef = viewParentEl(elView);
elView = elView.parent;
elDef = viewParentEl(elView) !;
elView = elView.parent !;
}
}
this.elDef = elDef;
@ -337,7 +337,7 @@ class DebugContext_ implements DebugContext {
for (let i = this.elDef.index + 1; i <= this.elDef.index + this.elDef.childCount; i++) {
const childDef = this.elView.def.nodes[i];
if (childDef.flags & NodeFlags.CatProvider) {
tokens.push(childDef.provider.token);
tokens.push(childDef.provider !.token);
}
i += childDef.childCount;
}
@ -389,7 +389,7 @@ class DebugContext_ implements DebugContext {
return NOOP;
}
};
logViewDef.factory(nodeLogger);
logViewDef.factory !(nodeLogger);
if (currRenderNodeIndex < renderNodeIndex) {
console.error('Illegal state: the ViewDefinitionFactory did not call the logger!');
(<any>console.error)(...values);
@ -408,14 +408,14 @@ function getRenderNodeIndex(viewDef: ViewDefinition, nodeIndex: number): number
return renderNodeIndex;
}
function findHostElement(view: ViewData): ElementData {
function findHostElement(view: ViewData): ElementData|null {
while (view && !isComponentView(view)) {
view = view.parent;
view = view.parent !;
}
if (view.parent) {
return asElementData(view.parent, viewParentEl(view).index);
return asElementData(view.parent, viewParentEl(view) !.index);
}
return undefined;
return null;
}
function collectReferences(view: ViewData, nodeDef: NodeDef, references: {[key: string]: any}) {
@ -440,11 +440,11 @@ function callWithDebugContext(action: DebugAction, fn: any, self: any, args: any
throw e;
}
_currentView.state |= ViewState.Errored;
throw viewWrappedDebugError(e, getCurrentDebugContext());
throw viewWrappedDebugError(e, getCurrentDebugContext() !);
}
}
export function getCurrentDebugContext(): DebugContext {
export function getCurrentDebugContext(): DebugContext|null {
return _currentView ? new DebugContext_(_currentView, _currentNodeIndex) : null;
}
@ -452,7 +452,7 @@ export function getCurrentDebugContext(): DebugContext {
class DebugRendererFactory2 implements RendererFactory2 {
constructor(private delegate: RendererFactory2) {}
createRenderer(element: any, renderData: RendererType2): Renderer2 {
createRenderer(element: any, renderData: RendererType2|null): Renderer2 {
return new DebugRenderer2(this.delegate.createRenderer(element, renderData));
}
}
@ -464,7 +464,7 @@ class DebugRenderer2 implements Renderer2 {
get data() { return this.delegate.data; }
destroyNode(node: any) {
removeDebugNodeFromIndex(getDebugNode(node));
removeDebugNodeFromIndex(getDebugNode(node) !);
if (this.delegate.destroyNode) {
this.delegate.destroyNode(node);
}
@ -513,7 +513,7 @@ class DebugRenderer2 implements Renderer2 {
insertBefore(parent: any, newChild: any, refChild: any): void {
const debugEl = getDebugNode(parent);
const debugChildEl = getDebugNode(newChild);
const debugRefEl = getDebugNode(refChild);
const debugRefEl = getDebugNode(refChild) !;
if (debugEl && debugChildEl && debugEl instanceof DebugElement) {
debugEl.insertBefore(debugRefEl, debugChildEl);
}

View File

@ -14,21 +14,21 @@ export function textDef(ngContentIndex: number, constants: string[]): NodeDef {
for (let i = 1; i < constants.length; i++) {
bindings[i - 1] = {
flags: BindingFlags.TypeProperty,
name: undefined,
ns: undefined,
nonMinifiedName: undefined,
securityContext: undefined,
name: null,
ns: null,
nonMinifiedName: null,
securityContext: null,
suffix: constants[i]
};
}
const flags = NodeFlags.TypeText;
return {
// will bet set by the view definition
index: undefined,
parent: undefined,
renderParent: undefined,
bindingIndex: undefined,
outputIndex: undefined,
index: -1,
parent: null,
renderParent: null,
bindingIndex: -1,
outputIndex: -1,
// regular values
flags,
childFlags: 0,
@ -40,18 +40,18 @@ export function textDef(ngContentIndex: number, constants: string[]): NodeDef {
childCount: 0, bindings,
bindingFlags: calcBindingFlags(bindings),
outputs: [],
element: undefined,
provider: undefined,
element: null,
provider: null,
text: {prefix: constants[0]},
query: undefined,
ngContent: undefined
query: null,
ngContent: null
};
}
export function createText(view: ViewData, renderHost: any, def: NodeDef): TextData {
let renderNode: any;
const renderer = view.renderer;
renderNode = renderer.createText(def.text.prefix);
renderNode = renderer.createText(def.text !.prefix);
const parentEl = getParentRenderElement(view, renderHost, def);
if (parentEl) {
renderer.appendChild(parentEl, renderNode);
@ -77,7 +77,7 @@ export function checkAndUpdateTextInline(
if (bindLen > 9 && checkAndUpdateBinding(view, def, 9, v9)) changed = true;
if (changed) {
let value = def.text.prefix;
let value = def.text !.prefix;
if (bindLen > 0) value += _addInterpolationPart(v0, bindings[0]);
if (bindLen > 1) value += _addInterpolationPart(v1, bindings[1]);
if (bindLen > 2) value += _addInterpolationPart(v2, bindings[2]);
@ -109,7 +109,7 @@ export function checkAndUpdateTextDynamic(view: ViewData, def: NodeDef, values:
for (let i = 0; i < values.length; i++) {
value = value + _addInterpolationPart(values[i], bindings[i]);
}
value = def.text.prefix + value;
value = def.text !.prefix + value;
const renderNode = asTextData(view, def.index).renderText;
view.renderer.setValue(renderNode, value);
}

View File

@ -19,7 +19,7 @@ import {Sanitizer, SecurityContext} from '../security';
// -------------------------------------
export interface ViewDefinition {
factory: ViewDefinitionFactory;
factory: ViewDefinitionFactory|null;
flags: ViewFlags;
updateDirectives: ViewUpdateFn;
updateRenderer: ViewUpdateFn;
@ -32,7 +32,7 @@ export interface ViewDefinition {
/** aggregated NodeFlags for all nodes **/
nodeFlags: NodeFlags;
rootNodeFlags: NodeFlags;
lastRenderRootNode: NodeDef;
lastRenderRootNode: NodeDef|null;
bindingCount: number;
outputCount: number;
/**
@ -91,8 +91,8 @@ export const enum ViewFlags {
export interface NodeDef {
flags: NodeFlags;
index: number;
parent: NodeDef;
renderParent: NodeDef;
parent: NodeDef|null;
renderParent: NodeDef|null;
/** this is checked against NgContentDef.index to find matched nodes */
ngContentIndex: number;
/** number of transitive children */
@ -123,11 +123,11 @@ export interface NodeDef {
* Used as a bloom filter.
*/
childMatchedQueries: number;
element: ElementDef;
provider: ProviderDef;
text: TextDef;
query: QueryDef;
ngContent: NgContentDef;
element: ElementDef|null;
provider: ProviderDef|null;
text: TextDef|null;
query: QueryDef|null;
ngContent: NgContentDef|null;
}
/**
@ -179,11 +179,11 @@ export const enum NodeFlags {
export interface BindingDef {
flags: BindingFlags;
ns: string;
name: string;
nonMinifiedName: string;
securityContext: SecurityContext;
suffix: string;
ns: string|null;
name: string|null;
nonMinifiedName: string|null;
securityContext: SecurityContext|null;
suffix: string|null;
}
export const enum BindingFlags {
@ -201,9 +201,9 @@ export const enum BindingFlags {
export interface OutputDef {
type: OutputType;
target: 'window'|'document'|'body'|'component';
target: 'window'|'document'|'body'|'component'|null;
eventName: string;
propName: string;
propName: string|null;
}
export const enum OutputType {ElementOutput, DirectiveOutput}
@ -217,26 +217,26 @@ export const enum QueryValueType {
}
export interface ElementDef {
name: string;
ns: string;
name: string|null;
ns: string|null;
/** ns, name, value */
attrs: [string, string, string][];
template: ViewDefinition;
componentProvider: NodeDef;
componentRendererType: RendererType2;
attrs: [string, string, string][]|null;
template: ViewDefinition|null;
componentProvider: NodeDef|null;
componentRendererType: RendererType2|null;
// closure to allow recursive components
componentView: ViewDefinitionFactory;
componentView: ViewDefinitionFactory|null;
/**
* visible public providers for DI in the view,
* as see from this element. This does not include private providers.
*/
publicProviders: {[tokenKey: string]: NodeDef};
publicProviders: {[tokenKey: string]: NodeDef}|null;
/**
* same as visiblePublicProviders, but also includes private providers
* that are located on this element.
*/
allProviders: {[tokenKey: string]: NodeDef};
handleEvent: ElementHandleEventFn;
allProviders: {[tokenKey: string]: NodeDef}|null;
handleEvent: ElementHandleEventFn|null;
}
export interface ElementHandleEventFn { (view: ViewData, eventName: string, event: any): boolean; }
@ -303,9 +303,9 @@ export interface ViewData {
root: RootData;
renderer: Renderer2;
// index of component provider / anchor.
parentNodeDef: NodeDef;
parent: ViewData;
viewContainerParent: ViewData;
parentNodeDef: NodeDef|null;
parent: ViewData|null;
viewContainerParent: ViewData|null;
component: any;
context: any;
// Attention: Never loop over this, as this will
@ -316,7 +316,7 @@ export interface ViewData {
nodes: {[key: number]: NodeData};
state: ViewState;
oldValues: any[];
disposables: DisposableFn[];
disposables: DisposableFn[]|null;
}
/**
@ -366,7 +366,7 @@ export function asTextData(view: ViewData, index: number): TextData {
export interface ElementData {
renderElement: any;
componentView: ViewData;
viewContainer: ViewContainerData;
viewContainer: ViewContainerData|null;
template: TemplateData;
}
@ -434,7 +434,7 @@ export interface RootData {
export abstract class DebugContext {
abstract get view(): ViewData;
abstract get nodeIndex(): number;
abstract get nodeIndex(): number|null;
abstract get injector(): Injector;
abstract get component(): any;
abstract get providerTokens(): any[];
@ -461,7 +461,7 @@ export interface Services {
checkNoChangesView(view: ViewData): void;
destroyView(view: ViewData): void;
resolveDep(
view: ViewData, elDef: NodeDef, allowPrivateServices: boolean, depDef: DepDef,
view: ViewData, elDef: NodeDef|null, allowPrivateServices: boolean, depDef: DepDef,
notFoundValue?: any): any;
createDebugContext(view: ViewData, nodeIndex: number): DebugContext;
handleEvent: ViewHandleEventFn;
@ -475,16 +475,16 @@ export interface Services {
* debug mode can hook it. It is lazily filled when `isDevMode` is known.
*/
export const Services: Services = {
setCurrentNode: undefined,
createRootView: undefined,
createEmbeddedView: undefined,
checkAndUpdateView: undefined,
checkNoChangesView: undefined,
destroyView: undefined,
resolveDep: undefined,
createDebugContext: undefined,
handleEvent: undefined,
updateDirectives: undefined,
updateRenderer: undefined,
dirtyParentQueries: undefined,
setCurrentNode: undefined !,
createRootView: undefined !,
createEmbeddedView: undefined !,
checkAndUpdateView: undefined !,
checkNoChangesView: undefined !,
destroyView: undefined !,
resolveDep: undefined !,
createDebugContext: undefined !,
handleEvent: undefined !,
updateDirectives: undefined !,
updateRenderer: undefined !,
dirtyParentQueries: undefined !,
};

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