Compare commits

...

185 Commits

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
95afaf495b test(compiler): refactor i18n integration test 2017-03-24 14:35:10 -07:00
d92930e975 docs: fixed broken links (#15455)
Closes #15446
2017-03-24 08:14:23 -07:00
c2892dada3 docs: revert the move of CONTRIBUTING.md to docs/CONTRIBUTING.md
Because the root path has a special meeting for GitHub, Jeremy, unicorns and red arrows.
2017-03-23 20:57:49 -07:00
b2b1195534 docs: update the contributing link one more time :-) 2017-03-23 19:26:25 -07:00
e1b09e3bcc docs: update CONTRIBUTING link in README.md 2017-03-23 19:25:46 -07:00
c65b75443e docs: add the 4.0.0 code name to the changelog 2017-03-23 17:46:02 -07:00
db0dca3fc1 docs: add a note about exclusion of symbols prefixed with ɵ from our public api surface (#15440) 2017-03-23 17:21:52 -07:00
7a715b2403 docs: add changelog for 4.0.0 2017-03-23 16:48:54 -07:00
1ba296644d release: cut the 4.0.0 release 2017-03-23 16:45:16 -07:00
b800a0c824 fix: prevent strictNullChecks support until #15432 is fixed (#15434) 2017-03-23 14:54:19 -07:00
0dda01e37c fix(compiler): correctly handle when toString is exported (#15430)
Fixes #15420
2017-03-23 13:38:01 -07:00
c8ab5cb0c5 fix(compiler): assume queries with no matches as static (#15429)
This has the side effect of allowing `@Input` and `@ContentChild`
on the same property if the query is static (see the bug description
for details).

Fixes #15417
2017-03-23 13:37:45 -07:00
92084f2b6a fix(platform-browser): setAttribute should work with xmlns namespace (#14874)
Closes #14865
2017-03-23 12:52:06 -07:00
08f2f08d74 fix(router): should pass new data to Observable when query params change (#15387)
Fixes #15290
2017-03-23 10:43:14 -07:00
376088da70 build(aio): delete content folder before doc-gen (#15414)
This should prevent false-positive e2e test runs where stale files
are left lying around.
2017-03-23 10:23:09 -07:00
73808dd38b build(aio): upgrade to @angular@4.0.0-rc.6 (#15412) 2017-03-22 23:52:43 -07:00
ee03418b10 release: cut the 4.0.0-rc.6 release 2017-03-22 23:09:47 -07:00
da700d1842 docs: move markdown docs from root dir to docs/ and remove obsolete files (#15410) 2017-03-22 22:50:12 -07:00
de87c47dd9 docs: spelling errors 2017-03-22 21:28:24 -07:00
1060805a1f docs: fix spelling 2017-03-22 21:28:24 -07:00
08d86751b9 fix(compiler): only log template deprecation warning once (#15364) 2017-03-22 21:26:53 -07:00
9319b5f329 docs(common): update ngFor docs to new as syntax (#15166) 2017-03-22 17:18:22 -07:00
26f6bd4d3b ci(travis): update excluded branch to g3 (#15391) 2017-03-22 17:15:38 -07:00
edb2571a59 docs: spelling error (#15406) 2017-03-22 17:14:56 -07:00
98cb974796 docs(router): fix typo in ParamMap api doc (#15397) 2017-03-22 17:14:11 -07:00
8b414222aa fix(aio): do not fallback to index.html for file requests (#15401)
Previously, all URLs were rewritten to `index.html` in order to support
deep-linking. This works when navigating to URLs that correspond to existing
resources. E.g. navigating to `/tutorial` returns `index.html` and then the
`DocViewer` takes over and requests `tutorial.json`.
Navigating to a non-existent URL (e.g. `/foo`), will return `index.html`, which
in turn requests (the non-existent) `foo.json` and throws an error when trying
to parse the returned `index.html` as JSON.

This commit fixes it by only rewriting URLs that do not request a file (i.e. do
not include a `.` in the last path segment).

Fixes #15398
2017-03-22 15:31:47 -07:00
ea49a95bd9 fix(upgrade): component injectors should not link the module injector tree (#15385) 2017-03-22 15:22:38 -07:00
a50d79df47 fix(compiler-cli): adding missing format xliff for the extractor (#15386)
To generate XLF files with ng-xi18n we could use the format parameter "xlf" or "xlif". The real name is "xliff" not "xlif", so this probably was a typo. This PR adds "xliff" as can be expected
2017-03-22 15:12:02 -07:00
64285a2171 docs: update 4.0.0-rc.5 release schedule (#15288) 2017-03-22 13:26:12 -07:00
941f194a83 docs: spelling errors (#15375) 2017-03-22 13:25:35 -07:00
8b4edcc7ad build(aio): output {@example} tags as <code-example> elements (#15382) 2017-03-22 13:24:40 -07:00
c58499786c fix(tsc-wrapped): use windows friendly path normalization in bundler (#15374)
Fixes #15289

PR Close #15374
2017-03-21 22:30:57 -05:00
1bcbcfd56f revert: build(aio): implement prerendering (#15346)
This reverts commit d0bc83ca27.

Protractor-based prerendering is flakey on Travis and takes several minutes to
complete, slowing down the build. Prerendering has a lower impact now that we
use a ServiceWorker. We will revisit in the future (probably using a
`PlatformServer`-based approach).

PR Close #15346
2017-03-21 19:05:36 -05:00
90d2518d9a fix(compiler): look for flat module resources using declaration module path (#15367)
`ngc` would look for flat module resources relative to the flat module index.
`ngc` now looks for flat module resources relative to the `.d.ts` file that declarates
the component.

Fixes #15221

PR Close #15367
2017-03-21 19:05:03 -05:00
7354949763 feat(tsc-wrapped): record original location of flattened symbols (#15367)
Added an "origins" section to the flat module `.metadata.json` files
that records where the original symbols was declared. This allows
correctly calculating relative path references recorded in metadata.
2017-03-21 19:05:00 -05:00
5efc86069f fix(forms): make composition event buffering configurable (#15256)
This commit fixes a regression where `ngModel` no longer syncs
letter by letter on Android devices, and instead syncs at the
end of every word. This broke when we introduced buffering of
IME events so IMEs like Pinyin keyboards or Katakana keyboards
wouldn't display composition strings. Unfortunately, iOS devices
and Android devices have opposite event behavior. Whereas iOS
devices fire composition events for IME keyboards only, Android
fires composition events for Latin-language keyboards. For
this reason, languages like English don't work as expected on
Android if we always buffer. So to support both platforms,
composition string buffering will only be turned on by default
for non-Android devices.

However, we have also added a `COMPOSITION_BUFFER_MODE` token
to make this configurable by the application. In some cases, apps
might might still want to receive intermediate values. For example,
some inputs begin searching based on Latin letters before a
character selection is made.

As a provider, this is fairly flexible. If you want to turn
composition buffering off, simply provide the token at the top
level:

```ts
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useValue: false}
]
```

Or, if you want to change the mode  based on locale or platform,
you can use a factory:

```ts
import {shouldUseBuffering} from 'my/lib';

....
providers: [
   {provide: COMPOSITION_BUFFER_MODE, useFactory: shouldUseBuffering}
]
```

Closes #15079.

PR Close #15256
2017-03-21 16:47:18 -05:00
97149f9424 fix(core): update peer dep on zone.js to ^0.8.5 (#15365)
Closes #15185

PR Close #15365
2017-03-21 16:47:01 -05:00
bac265fdc2 refactor(core): misc cleanup (#15366)
PR Close #15366
2017-03-21 16:46:51 -05:00
e59e5e24b9 build(aio): upgrade to rxjs@5.2.0 2017-03-21 15:20:29 -05:00
9e5d4781cb refactor(aio): cleanup polyfill imports and realign them with the latest cli blueprint
This shouldn't change anything. But it's interesting that we used to have this  import
that seemed bogus, but there were no compilation or rutime errors.
2017-03-21 15:20:28 -05:00
fc1f6efe0d build(aio): fix paths to "index" pages
Content pages like `tutorial/index.md` were being mapped to `tutorial.index.json`,
which meant that they could only be rendered if you browsed to `/tutorial/index`.

This didn't sit well so now these pages are mapped to `tutorial.json`, which
means that you browser to them via `/tutorial/` or just `/tutorial`.

Fixed #15335
2017-03-21 15:20:28 -05:00
c9710d4fb5 build(aio): upgrade @angular/cli to 1.0.0-rc.4 2017-03-21 15:20:28 -05:00
cf16f3b0dd build(aio): update @angular to 4.0.0-rc.5 and zone.js to 0.8.4 2017-03-21 15:20:28 -05:00
a9e91115bf build(aio): add version into navigation.json
The navigation.json is now passed through the dgeni pipeline.
The source file has been moved to `aio/content/navigation.json`
but the generated file will now appear where the original source file
was found, `aio/src/content/navigation.json`.

Everything inside `aio/src/content` is now generated and ignored by git.

The `processNavigationMap` processor in this commit adds the current version
information to the navigation.json file and verifies the relative urls in
the file map to real documents.

The navigationService exposes the versionInfo as an observable, which the
AppComponent renders at the top of the sidenav.
2017-03-21 15:20:28 -05:00
90f699fdcf build(aio): ensure that internal document links work with base href 2017-03-21 15:20:28 -05:00
fd7b855cfc test(aio): fix test descriptions for ordering of processors 2017-03-21 15:20:28 -05:00
20aab64c65 test(aio): use MockLogger in AppComponent tests
This component sends a lot of messages to the console, which makes the
test run less easy to follow.
2017-03-21 15:20:28 -05:00
2eb027a793 build(aio): don't process unnecessary example files in doc-gen
This lowers the `yarn docs` processing time by about 40% (from 50 secs
to 30 secs).
2017-03-21 15:20:28 -05:00
b0a7bc77ee build(aio): remove cheatsheet processing and content
This will be replaced by a single file migrated from angular.io
2017-03-21 15:20:28 -05:00
4e10faf1eb build(aio): add version into navigation.json
The navigation.json is now passed through the dgeni pipeline.
The source file has been moved to `aio/content/navigation.json`
but the generated file will now appear where the original source file
was found, `aio/src/content/navigation.json`.

Everything inside `aio/src/content` is now generated and ignored by git.

The `processNavigationMap` processor in this commit adds the current version
information to the navigation.json file and verifies the relative urls in
the file map to real documents.

The navigationService exposes the versionInfo as an observable, which the
AppComponent renders at the top of the sidenav.
2017-03-21 15:20:28 -05:00
a0c6d44e18 build(aio): ensure that internal document links work with base href 2017-03-21 15:20:28 -05:00
9bc998c7a1 build(aio): use forked version of Rho rendering engine
The original Rho is too strict when it comes to markdown headings.
It requires that there be a blank line separating the heading and the
next paragraph.  The forked version here fixes that; but the Rho project
will not merge it as it goes against there basic rules.
2017-03-21 15:20:28 -05:00
1a0c6d89b1 build(aio): do not render ignored docs 2017-03-21 15:20:28 -05:00
8c12374c4c build(aio): do not render private classes and members 2017-03-21 15:20:28 -05:00
45e2126273 refactor(aio): removed dead code 2017-03-21 15:20:28 -05:00
41497b052d feat(aio): font change and toolbar shadow 2017-03-21 15:20:28 -05:00
068cad1c1b build: update to angular 4.0.0-rc.4 and service-worker@1.0.0-beta.7 2017-03-21 15:20:28 -05:00
31ef92fc36 build(aio): fix generated github links
The change from `modules` to `packages` needed to be applied to these links.
2017-03-21 15:20:28 -05:00
b4081e3713 build(aio): update to dgeni-packages 0.17.0
This new version fixes the problem with mistaking
content inside inline HTML blocks as tags

Related to #15199
2017-03-21 15:20:28 -05:00
c8b4a33a7f ci(aio): lower prerender browser instances
Hopefully this will reduce aio test flakes
2017-03-21 15:20:28 -05:00
a13ddf2e8a feat(aio): expand nav menu branch of select item on page load 2017-03-21 15:20:28 -05:00
64beae9527 fix(core): mark components for check when host events trigger. (#15359)
Fixes #15352

PR Close #15359
2017-03-21 14:27:01 -05:00
15a082c74e fix(platform-server): throw a better error message for relative URLs (#15357)
Unlike in the browser, on the server there is no concept of a document origin.
Thus, it is illegal to make requests for relative URLs against Http on platform-server.

Currently this fails with a vague error:

Error: Uncaught (in promise): Error at resolvePromise

This change adds explicit validation and a friendlier error message:

Error: URLs requested via Http on the server must be absolute. URL: /testing

Another option considered was to track the concept of an origin for the platform
and automatically prepend it to relative URLs. This would cause automatic "local
RPCs" to be made, though, which would be an unexpected and undesirable default
behavior.

Fixes #15349

PR Close #15357
2017-03-21 14:26:51 -05:00
fbccd5cd38 fix(animations): ensure empty animate() steps work at the end of a sequence (#15328)
Closes #15310
Closes #15328

PR Close #15328
2017-03-21 14:26:43 -05:00
1e8b132ade refactor(compiler): only produce log expressions for elements / text (#15350)
This change reduces the amount of generated code by only adding `log`
calls for elements and text nodes.

We need the `log` calls to allow users to jump to the right place
in the template via source maps. However, we only need it for element
and text nodes, but not for directives, queries, … as for them we 
first locate the corresponding element or text node.

Related to #15239

PR Close #15350
2017-03-21 14:26:30 -05:00
431eb309f3 fix(core): provide NgModuleRef in ViewContainerRef.createComponent. (#15350)
This is needed to support the corner cases:
- usage of a `ComponentFactory` that was created on the fly via `Compiler`
- overwriting of the `NgModuleRef` that is associated to a
  `ComponentFactory` by the `ComponentFactoryResolver` from
  which it was read.

Fixes #15241
2017-03-21 14:26:26 -05:00
8e6995c91e fix(core): stringify shouldn't throw when toString returns null/undefined (#14975)
Fixes #14948

PR Close #14975
2017-03-21 12:20:44 -05:00
0759911431 docs(compiler-cli): mention that .ngsummary.json files should be gitignore'd (#15047)
PR Close #15047
2017-03-21 12:20:38 -05:00
1d7693c1e1 fix(compiler): use attribute id to merge translations (#15302)
We extracted ids from i18n attributes but forgot to use them when merging the translations, resulting in an error about missing translations even when they were correctly defined.

Fixes #15234

PR Close #15302
2017-03-21 12:20:31 -05:00
16e0423085 revert: feat(compiler-cli): support metadata file aliases (#15331)
This reverts commit 0ab49d4cec.

PR Close #15331
2017-03-21 12:20:14 -05:00
c2ffb6bfcd build: remove use of alias metadata (#15331) 2017-03-21 12:20:06 -05:00
2489e4ba1b fix(animations): correct the main entry path in package.json (#15300)
PR Close #15300
2017-03-20 22:36:37 -05:00
94da80148e fix(animations): stringify boolean values as 1 and 0 (#15311)
Closes #15247
Closes #15311

PR Close #15311
2017-03-20 22:36:29 -05:00
764e90f9bb fix(compiler): don’t call check if we don’t need to (#15322)
If a directive has not bindings nor has a `ngDoCheck` / `ngOnInit`
lifecycle hook, don’t generate a `check` call.

This does not have an impact on the behavior, but produces
less code.

PR Close #15322
2017-03-20 22:36:20 -05:00
9bf2fb4a74 fix(animations): ensure enter/leave cancellations work (#15323)
Closes #15315
Closes #15323

PR Close #15323
2017-03-20 22:36:11 -05:00
de3d2eeeba fix(platform-server): interpret Native view encapsulation as Emulated on the server (#15155)
PR Close #15155
2017-03-20 17:14:09 -05:00
a805d00256 ci(forms): add tina as secondary for forms (#15262)
PR Close #15262
2017-03-20 17:13:52 -05:00
61135bc842 fix: remove left over debugger statement (#15309)
PR Close #15309
2017-03-20 17:13:44 -05:00
fa36ffda14 Revert "fix(compiler): shouldn't throw when Symbol is used as DI token (#13701)" (#15319)
This reverts commit 8b5c6b2732.

This feature is not compatible with the `Injector.get` which now only 
takes `Type` or `InjectableToken`. `Symbol` is not a valid type.

Closes #15183

PR Close #15319
2017-03-20 17:13:37 -05:00
d3eda7a5b5 feat(router): add ParamMap.keys to get a list of parameters 2017-03-20 09:19:32 -07:00
a755b715ed feat(router): introduce ParamMap to access parameters
The Router use the type `Params` for all of:
- position parameters,
- matrix parameters,
- query parameters.

`Params` is defined as follow `type Params = {[key: string]: any}`

Because parameters can either have single or multiple values, the type should
actually be `type Params = {[key: string]: string | string[]}`.

The client code often assumes that parameters have single values, as in the
following exemple:

```
class MyComponent {
sessionId: Observable<string>;

constructor(private route: ActivatedRoute) {}

ngOnInit() {
    this.sessionId = this.route
      .queryParams
      .map(params => params['session_id'] || 'None');
}
}

```

The problem here is that `params['session_id']` could be `string` or `string[]`
but the error is not caught at build time because of the `any` type.

Fixing the type as describe above would break the build because `sessionId`
would becomes an `Observable<string | string[]>`.

However the client code knows if it expects a single or multiple values. By
using the new `ParamMap` interface the user code can decide when it needs a
single value (calling `ParamMap.get(): string`) or multiple values (calling
`ParamMap.getAll(): string[]`).

The above exemple should be rewritten as:

```
class MyComponent {
sessionId: Observable<string>;

constructor(private route: ActivatedRoute) {}

ngOnInit() {
    this.sessionId = this.route
      .queryParamMap
      .map(paramMap => paramMap.get('session_id') || 'None');
}
}

```

Added APIs:
- `interface ParamMap`,
- `ActivatedRoute.paramMap: ParamMap`,
- `ActivatedRoute.queryParamMap: ParamMap`,
- `ActivatedRouteSnapshot.paramMap: ParamMap`,
- `ActivatedRouteSnapshot.queryParamMap: ParamMap`,
- `UrlSegment.parameterMap: ParamMap`
2017-03-20 09:19:32 -07:00
a9d5de0e56 refactor(router): misc minor updates 2017-03-20 09:19:32 -07:00
f634c62cb3 test: add systemjs+umd integration test (#14196)
This test ensures the `__esModule` is set on UMD bundles, thus making them compatible with SystemJS@^0.22.3.

Followup from https://github.com/frankwallis/plugin-typescript/issues/185.

PR Close #14196
2017-03-19 12:23:07 -05:00
f8c075ae27 fix(core): don’t create a comment for components with empty template. (#15260)
Fixes #15143

PR Close #15260
2017-03-19 12:22:26 -05:00
aeb99645bb test(animations): test various combinations of animations with host bindings (#15251)
PR Close #15251
2017-03-19 12:21:54 -05:00
0d3e314df0 fix(core): trigger host animations for elements that are removed. (#15251)
Fixes #14813
Fixes #15193
2017-03-19 12:21:42 -05:00
28ce68a13d refactor(core): view engine - change BindingType to BindingFlags (#15251) 2017-03-19 12:21:37 -05:00
80075afe8a fix(animations): only process element nodes through the animation engine (#15268)
Closes #15267
Closes #15268

PR Close #15268
2017-03-19 10:50:07 -05:00
bcc29ffdd1 build: update rollup (#15258)
PR Close #15258
2017-03-17 17:39:19 -05:00
0c43535ccc fix(core): only apply WrappedValue to the binding of the pipe (#15257)
Previously, a pipe that returned a `WrappedValue` would force the change
of the next bound property, independent of the binding in which the pipe
was used.

Now only the binding in which the `WrappedValue` is used will be assumed
as changed.

Fixes #15116

PR Close #15257
2017-03-17 17:38:36 -05:00
49829b4a4d build: add package names to secondary endpoint package.json files (#15253)
Fixes #14736

PR Close #15253
2017-03-17 16:52:55 -05:00
5c5c2ae405 fix(platform-server): setup NoopAnimationsModule in ServerModule by default (#15131)
This is so that server side rendering does not throw an exception when it encounters animations on the server side and does not need the user to explicitly setup NoopAnimationsModule in their app server module.

Fixes #15098, #14784.

PR Close #15131
2017-03-17 16:21:51 -05:00
6e9264a79c fix(tsc-wrapped): emit flat module format correctly on Windows (#15215)
File name needed to be normalized before comparison when using
synthetic file names.

Fixes #15192

PR Close #15215
2017-03-17 15:35:28 -05:00
a6fb78ee3c fix(animations): make sure non-transitioned leave operations cancel existing animations (#15254)
Closes #15213

PR Close #15254
2017-03-17 15:35:11 -05:00
d0bc83ca27 build(aio): implement prerendering
The current implementation is based on @igorminar's [angular-io-v42][1]. It is
using Protractor to request all docs URLs, let them fallback to `/index.html`
and save the rendered page.

[1]: https://github.com/IgorMinar/angular-io-v42/tree/05508ab3/tools/prerenderer

Fixes #15104
2017-03-17 15:31:22 -05:00
b5b2fed54d refactor(aio): re-arrange npm scripts 2017-03-17 15:31:22 -05:00
4cef5dddc6 build(aio): use own .gitignore file 2017-03-17 15:31:22 -05:00
f92591054b fix(animations): make sure easing values work with web-animations (#15195)
Closes #15115
Closes #15195

PR Close #15195
2017-03-17 13:53:19 -05:00
2a0e55ffb5 fix(core): allow tree shaking of component factories and styles (#15214)
Closure compiler is very sensitive to top level function calls.
This commit makes the function calls `createComponentFactory`
and `createRendererTypeV2` logic-less.

Fixes #15181

PR Close #15214
2017-03-17 13:52:57 -05:00
9429032da1 feat(upgrade): use ComponentFactory.inputs/outputs/ngContentSelectors (#15214)
DEPRECATION:
- the arguments `inputs` / `outputs` / `ngContentSelectors` of `downgradeComponent`
  are no longer used as Angular calculates these automatically now.
- Compiler.getNgContentSelectors is deprecated. Use
  ComponentFactory.ngContentSelectors instead.
2017-03-17 13:52:50 -05:00
791534f2f4 feat(core): expose inputs, outputs and ngContentSelectors on ComponentFactory. (#15214)
E.g. for a component like this:
```
@Component({
  template: ‘<ng-content select=“child”></ng-content>’
})
class MyComp {
  @Input(‘aInputName’)
  aInputProp: string;

  @Output(‘aEventName’)
  aOuputProp: EventEmitter<any>;
}
```

the `ComponentFactory` will now contain the following:
- `inputs = {aInputProp: ‘aInputName’}`
- `outputs = {aOutputProp: ‘aOutputName’}`
- `ngContentSelectors = [‘child’]`
2017-03-17 13:52:41 -05:00
604546c287 refactor(upgrade): don’t rely on compiler internals (#15214)
Uses `Element.matches` to match selectors, instead
of copying the code from our compiler.
2017-03-17 13:52:34 -05:00
c66437fc13 fix(animations): only treat view removals as void state transitions (#15245)
Closes #15223

PR Close #15245
2017-03-17 13:48:25 -05:00
8415910375 fix(compiler): add an empty content for source file of non mapped code. (#15246)
Before this when using ngc, tools tried to load `ng://…<component>.ts`
if `…<component>.ts` was the source file of a template.

PR Close #15246
2017-03-17 13:48:09 -05:00
5486e5417b feat(forms): allow to compile forms in strictNullChecks mode (#14679)
Closes #14667

PR Close #14679
2017-03-17 13:47:12 -05:00
2d78c8cc05 docs: add changelog for 4.0.0-rc.5 2017-03-17 10:18:16 -07:00
52bed7f9b3 release: cut the 4.0.0-rc.5 release 2017-03-17 10:16:53 -07:00
7fb45283df fix(compiler-cli): update the tsc-wrapped dependency version (#15226) 2017-03-17 09:41:28 -07:00
430 changed files with 9247 additions and 6437 deletions

4
.gitignore vendored
View File

@ -26,7 +26,3 @@ yarn-error.log
# rollup-test output
/modules/rollup-test/dist/
# angular.io
/aio/src/content/docs
/aio/dist

View File

@ -21,6 +21,7 @@
# vicb - Victor Berchet
# vikerman - Vikram Subramanian
# wardbell - Ward Bell
# tinayuangao - Tina Gao
version: 2
@ -155,7 +156,7 @@ groups:
- "packages/forms/*"
users:
- kara #primary
# needs secondary
- tinayuangao #secondary
- IgorMinar #fallback
- mhevery #fallback
@ -175,7 +176,8 @@ groups:
- "packages/language-service/*"
users:
- chuckjaz #primary
# needs secondary
- tbosch #secondary
- vicb
- IgorMinar #fallback
- mhevery #fallback
@ -184,8 +186,8 @@ groups:
files:
- "packages/router/*"
users:
- vicb #primary
# needs secondary
- jasonaden
- vicb
- IgorMinar #fallback
- mhevery #fallback

View File

@ -19,7 +19,7 @@ addons:
- secure: "L7nrZwkAtFtYrP2DykPXgZvEKjkv0J/TwQ/r2QGxFTaBq4VZn+2Dw0YS7uCxoMqYzDwH0aAOqxoutibVpk8Z/16nE3tNmU5RzltMd6Xmt3qU2f/JDQLMo6PSlBodnjOUsDHJgmtrcbjhqrx/znA237BkNUu6UZRT7mxhXIZpn0U="
branches:
except:
- g3_v2_0
- g3
cache:
yarn: true

View File

@ -1,3 +1,181 @@
<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)
### Bug Fixes
* **compiler:** assume queries with no matches as static ([#15429](https://github.com/angular/angular/issues/15429)) ([c8ab5cb](https://github.com/angular/angular/commit/c8ab5cb)), closes [#15417](https://github.com/angular/angular/issues/15417)
* **compiler:** correctly handle when `toString` is exported ([#15430](https://github.com/angular/angular/issues/15430)) ([0dda01e](https://github.com/angular/angular/commit/0dda01e)), closes [#15420](https://github.com/angular/angular/issues/15420)
* **platform-browser:** setAttribute should work with xmlns namespace ([#14874](https://github.com/angular/angular/issues/14874)) ([92084f2](https://github.com/angular/angular/commit/92084f2)), closes [#14865](https://github.com/angular/angular/issues/14865)
* **router:** should pass new data to Observable when query params change ([#15387](https://github.com/angular/angular/issues/15387)) ([08f2f08](https://github.com/angular/angular/commit/08f2f08)), closes [#15290](https://github.com/angular/angular/issues/15290)
* prevent strictNullChecks support until [#15432](https://github.com/angular/angular/issues/15432) is fixed ([#15434](https://github.com/angular/angular/issues/15434)) ([b800a0c](https://github.com/angular/angular/commit/b800a0c))
<a name="4.0.0-rc.6"></a>
# [4.0.0-rc.6](https://github.com/angular/angular/compare/4.0.0-rc.5...4.0.0-rc.6) (2017-03-23)
### Bug Fixes
* **animations:** correct the main entry path in package.json ([#15300](https://github.com/angular/angular/issues/15300)) ([2489e4b](https://github.com/angular/angular/commit/2489e4b))
* **animations:** ensure empty animate() steps work at the end of a sequence ([#15328](https://github.com/angular/angular/issues/15328)) ([fbccd5c](https://github.com/angular/angular/commit/fbccd5c)), closes [#15310](https://github.com/angular/angular/issues/15310)
* **animations:** ensure enter/leave cancellations work ([#15323](https://github.com/angular/angular/issues/15323)) ([9bf2fb4](https://github.com/angular/angular/commit/9bf2fb4)), closes [#15315](https://github.com/angular/angular/issues/15315)
* **animations:** make sure easing values work with web-animations ([#15195](https://github.com/angular/angular/issues/15195)) ([f925910](https://github.com/angular/angular/commit/f925910)), closes [#15115](https://github.com/angular/angular/issues/15115)
* **animations:** make sure non-transitioned leave operations cancel existing animations ([#15254](https://github.com/angular/angular/issues/15254)) ([a6fb78e](https://github.com/angular/angular/commit/a6fb78e)), closes [#15213](https://github.com/angular/angular/issues/15213)
* **animations:** only process element nodes through the animation engine ([#15268](https://github.com/angular/angular/issues/15268)) ([80075af](https://github.com/angular/angular/commit/80075af)), closes [#15267](https://github.com/angular/angular/issues/15267)
* **animations:** only treat view removals as `void` state transitions ([#15245](https://github.com/angular/angular/issues/15245)) ([c66437f](https://github.com/angular/angular/commit/c66437f)), closes [#15223](https://github.com/angular/angular/issues/15223)
* **animations:** stringify boolean values as `1` and `0` ([#15311](https://github.com/angular/angular/issues/15311)) ([94da801](https://github.com/angular/angular/commit/94da801)), closes [#15247](https://github.com/angular/angular/issues/15247)
* **compiler:** add an empty content for source file of non mapped code. ([#15246](https://github.com/angular/angular/issues/15246)) ([8415910](https://github.com/angular/angular/commit/8415910))
* **compiler:** dont call `check` if we dont need to ([#15322](https://github.com/angular/angular/issues/15322)) ([764e90f](https://github.com/angular/angular/commit/764e90f))
* **compiler:** look for flat module resources using declaration module path ([#15367](https://github.com/angular/angular/issues/15367)) ([90d2518](https://github.com/angular/angular/commit/90d2518)), closes [#15221](https://github.com/angular/angular/issues/15221)
* **compiler:** only log template deprecation warning once ([#15364](https://github.com/angular/angular/issues/15364)) ([08d8675](https://github.com/angular/angular/commit/08d8675))
* **compiler:** use attribute id to merge translations ([#15302](https://github.com/angular/angular/issues/15302)) ([1d7693c](https://github.com/angular/angular/commit/1d7693c)), closes [#15234](https://github.com/angular/angular/issues/15234)
* **compiler-cli:** adding missing format xliff for the extractor ([#15386](https://github.com/angular/angular/issues/15386)) ([a50d79d](https://github.com/angular/angular/commit/a50d79d))
* **core:** allow tree shaking of component factories and styles ([#15214](https://github.com/angular/angular/issues/15214)) ([2a0e55f](https://github.com/angular/angular/commit/2a0e55f)), closes [#15181](https://github.com/angular/angular/issues/15181)
* **core:** dont create a comment for components with empty template. ([#15260](https://github.com/angular/angular/issues/15260)) ([f8c075a](https://github.com/angular/angular/commit/f8c075a)), closes [#15143](https://github.com/angular/angular/issues/15143)
* **core:** mark components for check when host events trigger. ([#15359](https://github.com/angular/angular/issues/15359)) ([64beae9](https://github.com/angular/angular/commit/64beae9)), closes [#15352](https://github.com/angular/angular/issues/15352)
* **core:** only apply `WrappedValue` to the binding of the pipe ([#15257](https://github.com/angular/angular/issues/15257)) ([0c43535](https://github.com/angular/angular/commit/0c43535)), closes [#15116](https://github.com/angular/angular/issues/15116)
* **core:** provide `NgModuleRef` in `ViewContainerRef.createComponent`. ([#15350](https://github.com/angular/angular/issues/15350)) ([431eb30](https://github.com/angular/angular/commit/431eb30)), closes [#15241](https://github.com/angular/angular/issues/15241)
* **core:** stringify shouldn't throw when toString returns null/undefined ([#14975](https://github.com/angular/angular/issues/14975)) ([8e6995c](https://github.com/angular/angular/commit/8e6995c)), closes [#14948](https://github.com/angular/angular/issues/14948)
* **core:** trigger host animations for elements that are removed. ([#15251](https://github.com/angular/angular/issues/15251)) ([0d3e314](https://github.com/angular/angular/commit/0d3e314)), closes [#14813](https://github.com/angular/angular/issues/14813) [#15193](https://github.com/angular/angular/issues/15193)
* **core:** update peer dep on zone.js to ^0.8.5 ([#15365](https://github.com/angular/angular/issues/15365)) ([97149f9](https://github.com/angular/angular/commit/97149f9)), closes [#15185](https://github.com/angular/angular/issues/15185)
* **forms:** make composition event buffering configurable ([#15256](https://github.com/angular/angular/issues/15256)) ([5efc860](https://github.com/angular/angular/commit/5efc860)), closes [#15079](https://github.com/angular/angular/issues/15079)
* **platform-server:** interpret Native view encapsulation as Emulated on the server ([#15155](https://github.com/angular/angular/issues/15155)) ([de3d2ee](https://github.com/angular/angular/commit/de3d2ee))
* **platform-server:** setup NoopAnimationsModule in ServerModule by default ([#15131](https://github.com/angular/angular/issues/15131)) ([5c5c2ae](https://github.com/angular/angular/commit/5c5c2ae)), closes [#15098](https://github.com/angular/angular/issues/15098) [#14784](https://github.com/angular/angular/issues/14784)
* **platform-server:** throw a better error message for relative URLs ([#15357](https://github.com/angular/angular/issues/15357)) ([15a082c](https://github.com/angular/angular/commit/15a082c)), closes [#15349](https://github.com/angular/angular/issues/15349)
* **tsc-wrapped:** emit flat module format correctly on Windows ([#15215](https://github.com/angular/angular/issues/15215)) ([6e9264a](https://github.com/angular/angular/commit/6e9264a)), closes [#15192](https://github.com/angular/angular/issues/15192)
* **tsc-wrapped:** use windows friendly path normalization in bundler ([#15374](https://github.com/angular/angular/issues/15374)) ([c584997](https://github.com/angular/angular/commit/c584997)), closes [#15289](https://github.com/angular/angular/issues/15289)
* **upgrade:** component injectors should not link the module injector tree ([#15385](https://github.com/angular/angular/issues/15385)) ([ea49a95](https://github.com/angular/angular/commit/ea49a95))
### Features
* **core:** expose `inputs`, `outputs` and `ngContentSelectors` on `ComponentFactory`. ([#15214](https://github.com/angular/angular/issues/15214)) ([791534f](https://github.com/angular/angular/commit/791534f))
* **router:** add `ParamMap.keys` to get a list of parameters ([d3eda7a](https://github.com/angular/angular/commit/d3eda7a))
* **router:** introduce `ParamMap` to access parameters ([a755b71](https://github.com/angular/angular/commit/a755b71))
* **tsc-wrapped:** record original location of flattened symbols ([#15367](https://github.com/angular/angular/issues/15367)) ([7354949](https://github.com/angular/angular/commit/7354949))
* **upgrade:** use `ComponentFactory.inputs/outputs/ngContentSelectors` ([#15214](https://github.com/angular/angular/issues/15214)) ([9429032](https://github.com/angular/angular/commit/9429032))
<a name="4.0.0-rc.5"></a>
# [4.0.0-rc.5](https://github.com/angular/angular/compare/4.0.0-rc.4...4.0.0-rc.5) (2017-03-17)
### Bug Fixes
* **compiler-cli:** update the tsc-wrapped dependency version ([#15226](https://github.com/angular/angular/issues/15226)) ([7fb4528](https://github.com/angular/angular/commit/7fb4528))
<a name="4.0.0-rc.4"></a>
# [4.0.0-rc.4](https://github.com/angular/angular/compare/4.0.0-rc.3...4.0.0-rc.4) (2017-03-17)
@ -67,7 +245,7 @@
Also, providers that are used by a directive / pipe / ngModule stay eager.
So the impact should be rather small.
* DebugNode.source no longer returns the source location of a node.
* DebugNode.source no longer returns the source location of a node.
Closes 14013

View File

@ -147,7 +147,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo
* All public API methods **must be documented**. (Details TBC).
* We follow [Google's JavaScript Style Guide][js-style-guide], but wrap all code at
**100 characters**. An automated formatter is available, see
[DEVELOPER.md](DEVELOPER.md#clang-format).
[DEVELOPER.md](docs/DEVELOPER.md#clang-format).
## <a name="commit"></a> Commit Message Guidelines
@ -263,7 +263,7 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
[dev-doc]: https://github.com/angular/angular/blob/master/DEVELOPER.md
[dev-doc]: https://github.com/angular/angular/blob/master/docs/DEVELOPER.md
[github]: https://github.com/angular/angular
[gitter]: https://gitter.im/angular/angular
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html

11
aio/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
# Ignore node_modules
node_modules
# Ignore npm/yarn debug log
npm-debug.log
yarn-error.log
# Ignore generated content
/dist
/src/content
/.sass-cache

View File

@ -1,18 +0,0 @@
@cheatsheetSection
Bootstrapping
@cheatsheetIndex 0
@description
{@target ts}`import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';`{@endtarget}
{@target js}Available from the `ng.platformBrowserDynamic` namespace{@endtarget}
@cheatsheetItem
syntax(ts):
`platformBrowserDynamic().bootstrapModule(AppModule);`|`platformBrowserDynamic().bootstrapModule`
syntax(js):
`document.addEventListener('DOMContentLoaded', function() {
ng.platformBrowserDynamic
.platformBrowserDynamic()
.bootstrapModule(app.AppModule);
});`|`platformBrowserDynamic().bootstrapModule`
description:
Bootstraps the app, using the root component from the specified `NgModule`. {@target js}Must be wrapped in the event listener to fire when the page loads.{@endtarget}

View File

@ -1,34 +0,0 @@
@cheatsheetSection
Built-in directives
@cheatsheetIndex 3
@description
{@target ts}`import { CommonModule } from '@angular/common';`{@endtarget}
{@target js}Available using the `ng.common.CommonModule` module{@endtarget}
@cheatsheetItem
syntax:
`<section *ngIf="showSection">`|`*ngIf`
description:
Removes or recreates a portion of the DOM tree based on the `showSection` expression.
@cheatsheetItem
syntax:
`<li *ngFor="let item of list">`|`*ngFor`
description:
Turns the li element and its contents into a template, and uses that to instantiate a view for each item in list.
@cheatsheetItem
syntax:
`<div [ngSwitch]="conditionExpression">
<ng-template [ngSwitchCase]="case1Exp">...</ng-template>
<ng-template ngSwitchCase="case2LiteralString">...</ng-template>
<ng-template ngSwitchDefault>...</ng-template>
</div>`|`[ngSwitch]`|`[ngSwitchCase]`|`ngSwitchCase`|`ngSwitchDefault`
description:
Conditionally swaps the contents of the div by selecting one of the embedded templates based on the current value of `conditionExpression`.
@cheatsheetItem
syntax:
`<div [ngClass]="{active: isActive, disabled: isDisabled}">`|`[ngClass]`
description:
Binds the presence of CSS classes on the element to the truthiness of the associated map values. The right-hand expression should return {class-name: true/false} map.

View File

@ -1,49 +0,0 @@
@cheatsheetSection
Class decorators
@cheatsheetIndex 5
@description
{@target ts}`import { Directive, ... } from '@angular/core';`{@endtarget}
{@target js}Available from the `ng.core` namespace{@endtarget}
@cheatsheetItem
syntax(ts):
`@Component({...})
class MyComponent() {}`|`@Component({...})`
syntax(js):
`var MyComponent = ng.core.Component({...}).Class({...})`|`ng.core.Component({...})`
description:
Declares that a class is a component and provides metadata about the component.
@cheatsheetItem
syntax(ts):
`@Directive({...})
class MyDirective() {}`|`@Directive({...})`
syntax(js):
`var MyDirective = ng.core.Directive({...}).Class({...})`|`ng.core.Directive({...})`
description:
Declares that a class is a directive and provides metadata about the directive.
@cheatsheetItem
syntax(ts):
`@Pipe({...})
class MyPipe() {}`|`@Pipe({...})`
syntax(js):
`var MyPipe = ng.core.Pipe({...}).Class({...})`|`ng.core.Pipe({...})`
description:
Declares that a class is a pipe and provides metadata about the pipe.
@cheatsheetItem
syntax(ts):
`@Injectable()
class MyService() {}`|`@Injectable()`
syntax(js):
`var OtherService = ng.core.Class(
{constructor: function() { }});
var MyService = ng.core.Class(
{constructor: [OtherService, function(otherService) { }]});`|`var MyService = ng.core.Class({constructor: [OtherService, function(otherService) { }]});`
description:
{@target ts}Declares that a class has dependencies that should be injected into the constructor when the dependency injector is creating an instance of this class.
{@endtarget}
{@target js}
Declares a service to inject into a class by providing an array with the services, with the final item being the function to receive the injected services.
{@endtarget}

View File

@ -1,38 +0,0 @@
@cheatsheetSection
Component configuration
@cheatsheetIndex 7
@description
{@target js}`ng.core.Component` extends `ng.core.Directive`,
so the `ng.core.Directive` configuration applies to components as well{@endtarget}
{@target ts}`@Component` extends `@Directive`,
so the `@Directive` configuration applies to components as well{@endtarget}
@cheatsheetItem
syntax:
`moduleId: module.id`|`moduleId:`
description:
If set, the `templateUrl` and `styleUrl` are resolved relative to the component.
@cheatsheetItem
syntax(ts):
`viewProviders: [MyService, { provide: ... }]`|`viewProviders:`
syntax(js):
`viewProviders: [MyService, { provide: ... }]`|`viewProviders:`
description:
List of dependency injection providers scoped to this component's view.
@cheatsheetItem
syntax:
`template: 'Hello {{name}}'
templateUrl: 'my-component.html'`|`template:`|`templateUrl:`
description:
Inline template or external template URL of the component's view.
@cheatsheetItem
syntax:
`styles: ['.primary {color: red}']
styleUrls: ['my-component.css']`|`styles:`|`styleUrls:`
description:
List of inline CSS styles or external stylesheet URLs for styling the components view.

View File

@ -1,30 +0,0 @@
@cheatsheetSection
Dependency injection configuration
@cheatsheetIndex 10
@description
@cheatsheetItem
syntax(ts):
`{ provide: MyService, useClass: MyMockService }`|`provide`|`useClass`
syntax(js):
`{ provide: MyService, useClass: MyMockService }`|`provide`|`useClass`
description:
Sets or overrides the provider for `MyService` to the `MyMockService` class.
@cheatsheetItem
syntax(ts):
`{ provide: MyService, useFactory: myFactory }`|`provide`|`useFactory`
syntax(js):
`{ provide: MyService, useFactory: myFactory }`|`provide`|`useFactory`
description:
Sets or overrides the provider for `MyService` to the `myFactory` factory function.
@cheatsheetItem
syntax(ts):
`{ provide: MyValue, useValue: 41 }`|`provide`|`useValue`
syntax(js):
`{ provide: MyValue, useValue: 41 }`|`provide`|`useValue`
description:
Sets or overrides the provider for `MyValue` to the value `41`.

View File

@ -1,86 +0,0 @@
@cheatsheetSection
Class field decorators for directives and components
@cheatsheetIndex 8
@description
{@target ts}`import { Input, ... } from '@angular/core';`{@endtarget}
{@target js}Available from the `ng.core` namespace{@endtarget}
@cheatsheetItem
syntax(ts):
`@Input() myProperty;`|`@Input()`
syntax(js):
`ng.core.Input(myProperty, myComponent);`|`ng.core.Input(`|`);`
description:
Declares an input property that you can update via property binding (example:
`<my-cmp [myProperty]="someExpression">`).
@cheatsheetItem
syntax(ts):
`@Output() myEvent = new EventEmitter();`|`@Output()`
syntax(js):
`myEvent = new ng.core.EventEmitter();
ng.core.Output(myEvent, myComponent);`|`ng.core.Output(`|`);`
description:
Declares an output property that fires events that you can subscribe to with an event binding (example: `<my-cmp (myEvent)="doSomething()">`).
@cheatsheetItem
syntax(ts):
`@HostBinding('class.valid') isValid;`|`@HostBinding('class.valid')`
syntax(js):
`ng.core.HostBinding('class.valid',
'isValid', myComponent);`|`ng.core.HostBinding('class.valid', 'isValid'`|`);`
description:
Binds a host element property (here, the CSS class `valid`) to a directive/component property (`isValid`).
@cheatsheetItem
syntax(ts):
`@HostListener('click', ['$event']) onClick(e) {...}`|`@HostListener('click', ['$event'])`
syntax(js):
`ng.core.HostListener('click',
['$event'], onClick(e) {...}, myComponent);`|`ng.core.HostListener('click', ['$event'], onClick(e)`|`);`
description:
Subscribes to a host element event (`click`) with a directive/component method (`onClick`), optionally passing an argument (`$event`).
@cheatsheetItem
syntax(ts):
`@ContentChild(myPredicate) myChildComponent;`|`@ContentChild(myPredicate)`
syntax(js):
`ng.core.ContentChild(myPredicate,
'myChildComponent', myComponent);`|`ng.core.ContentChild(myPredicate,`|`);`
description:
Binds the first result of the component content query (`myPredicate`) to a property (`myChildComponent`) of the class.
@cheatsheetItem
syntax(ts):
`@ContentChildren(myPredicate) myChildComponents;`|`@ContentChildren(myPredicate)`
syntax(js):
`ng.core.ContentChildren(myPredicate,
'myChildComponents', myComponent);`|`ng.core.ContentChildren(myPredicate,`|`);`
description:
Binds the results of the component content query (`myPredicate`) to a property (`myChildComponents`) of the class.
@cheatsheetItem
syntax(ts):
`@ViewChild(myPredicate) myChildComponent;`|`@ViewChild(myPredicate)`
syntax(js):
`ng.core.ViewChild(myPredicate,
'myChildComponent', myComponent);`|`ng.core.ViewChild(myPredicate,`|`);`
description:
Binds the first result of the component view query (`myPredicate`) to a property (`myChildComponent`) of the class. Not available for directives.
@cheatsheetItem
syntax(ts):
`@ViewChildren(myPredicate) myChildComponents;`|`@ViewChildren(myPredicate)`
syntax(js):
`ng.core.ViewChildren(myPredicate,
'myChildComponents', myComponent);`|`ng.core.ViewChildren(myPredicate,`|`);`
description:
Binds the results of the component view query (`myPredicate`) to a property (`myChildComponents`) of the class. Not available for directives.

View File

@ -1,23 +0,0 @@
@cheatsheetSection
Directive configuration
@cheatsheetIndex 6
@description
{@target ts}`@Directive({ property1: value1, ... })`{@endtarget}
{@target js}`ng.core.Directive({ property1: value1, ... }).Class({...})`{@endtarget}
@cheatsheetItem
syntax:
`selector: '.cool-button:not(a)'`|`selector:`
description:
Specifies a CSS selector that identifies this directive within a template. Supported selectors include `element`,
`[attribute]`, `.class`, and `:not()`.
Does not support parent-child relationship selectors.
@cheatsheetItem
syntax(ts):
`providers: [MyService, { provide: ... }]`|`providers:`
syntax(js):
`providers: [MyService, { provide: ... }]`|`providers:`
description:
List of dependency injection providers for this directive and its children.

View File

@ -1,12 +0,0 @@
@cheatsheetSection
Forms
@cheatsheetIndex 4
@description
{@target ts}`import { FormsModule } from '@angular/forms';`{@endtarget}
{@target js}Available using the `ng.forms.FormsModule` module{@endtarget}
@cheatsheetItem
syntax:
`<input [(ngModel)]="userName">`|`[(ngModel)]`
description:
Provides two-way data-binding, parsing, and validation for form controls.

View File

@ -1,86 +0,0 @@
@cheatsheetSection
Directive and component change detection and lifecycle hooks
@cheatsheetIndex 9
@description
{@target ts}(implemented as class methods){@endtarget}
{@target js}(implemented as component properties){@endtarget}
@cheatsheetItem
syntax(ts):
`constructor(myService: MyService, ...) { ... }`|`constructor(myService: MyService, ...)`
syntax(js):
`constructor: function(MyService, ...) { ... }`|`constructor: function(MyService, ...)`
description:
Called before any other lifecycle hook. Use it to inject dependencies, but avoid any serious work here.
@cheatsheetItem
syntax(ts):
`ngOnChanges(changeRecord) { ... }`|`ngOnChanges(changeRecord)`
syntax(js):
`ngOnChanges: function(changeRecord) { ... }`|`ngOnChanges: function(changeRecord)`
description:
Called after every change to input properties and before processing content or child views.
@cheatsheetItem
syntax(ts):
`ngOnInit() { ... }`|`ngOnInit()`
syntax(js):
`ngOnInit: function() { ... }`|`ngOnInit: function()`
description:
Called after the constructor, initializing input properties, and the first call to `ngOnChanges`.
@cheatsheetItem
syntax(ts):
`ngDoCheck() { ... }`|`ngDoCheck()`
syntax(js):
`ngDoCheck: function() { ... }`|`ngDoCheck: function()`
description:
Called every time that the input properties of a component or a directive are checked. Use it to extend change detection by performing a custom check.
@cheatsheetItem
syntax(ts):
`ngAfterContentInit() { ... }`|`ngAfterContentInit()`
syntax(js):
`ngAfterContentInit: function() { ... }`|`ngAfterContentInit: function()`
description:
Called after `ngOnInit` when the component's or directive's content has been initialized.
@cheatsheetItem
syntax(ts):
`ngAfterContentChecked() { ... }`|`ngAfterContentChecked()`
syntax(js):
`ngAfterContentChecked: function() { ... }`|`ngAfterContentChecked: function()`
description:
Called after every check of the component's or directive's content.
@cheatsheetItem
syntax(ts):
`ngAfterViewInit() { ... }`|`ngAfterViewInit()`
syntax(js):
`ngAfterViewInit: function() { ... }`|`ngAfterViewInit: function()`
description:
Called after `ngAfterContentInit` when the component's view has been initialized. Applies to components only.
@cheatsheetItem
syntax(ts):
`ngAfterViewChecked() { ... }`|`ngAfterViewChecked()`
syntax(js):
`ngAfterViewChecked: function() { ... }`|`ngAfterViewChecked: function()`
description:
Called after every check of the component's view. Applies to components only.
@cheatsheetItem
syntax(ts):
`ngOnDestroy() { ... }`|`ngOnDestroy()`
syntax(js):
`ngOnDestroy: function() { ... }`|`ngOnDestroy: function()`
description:
Called once, before the instance is destroyed.

View File

@ -1,58 +0,0 @@
@cheatsheetSection
NgModules
@cheatsheetIndex 1
@description
{@target ts}`import { NgModule } from '@angular/core';`{@endtarget}
{@target js}Available from the `ng.core` namespace{@endtarget}
@cheatsheetItem
syntax(ts):
`@NgModule({ declarations: ..., imports: ...,
exports: ..., providers: ..., bootstrap: ...})
class MyModule {}`|`NgModule`
description:
Defines a module that contains components, directives, pipes, and providers.
syntax(js):
`ng.core.NgModule({declarations: ..., imports: ...,
exports: ..., providers: ..., bootstrap: ...}).
Class({ constructor: function() {}})`
description:
Defines a module that contains components, directives, pipes, and providers.
@cheatsheetItem
syntax:
`declarations: [MyRedComponent, MyBlueComponent, MyDatePipe]`|`declarations:`
description:
List of components, directives, and pipes that belong to this module.
@cheatsheetItem
syntax(ts):
`imports: [BrowserModule, SomeOtherModule]`|`imports:`
description:
List of modules to import into this module. Everything from the imported modules
is available to `declarations` of this module.
syntax(js):
`imports: [ng.platformBrowser.BrowserModule, SomeOtherModule]`|`imports:`
description:
List of modules to import into this module. Everything from the imported modules
is available to `declarations` of this module.
@cheatsheetItem
syntax:
`exports: [MyRedComponent, MyDatePipe]`|`exports:`
description:
List of components, directives, and pipes visible to modules that import this module.
@cheatsheetItem
syntax:
`providers: [MyService, { provide: ... }]`|`providers:`
description:
List of dependency injection providers visible both to the contents of this module and to importers of this module.
@cheatsheetItem
syntax:
`bootstrap: [MyAppComponent]`|`bootstrap:`
description:
List of components to bootstrap when this module is bootstrapped.

View File

@ -1,170 +0,0 @@
@cheatsheetSection
Routing and navigation
@cheatsheetIndex 11
@description
{@target ts}`import { Routes, RouterModule, ... } from '@angular/router';`{@endtarget}
{@target js}Available from the `ng.router` namespace{@endtarget}
@cheatsheetItem
syntax(ts):
`const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'path/:routeParam', component: MyComponent },
{ path: 'staticPath', component: ... },
{ path: '**', component: ... },
{ path: 'oldPath', redirectTo: '/staticPath' },
{ path: ..., component: ..., data: { message: 'Custom' } }
]);
const routing = RouterModule.forRoot(routes);`|`Routes`
syntax(js):
`var routes = [
{ path: '', component: HomeComponent },
{ path: ':routeParam', component: MyComponent },
{ path: 'staticPath', component: ... },
{ path: '**', component: ... },
{ path: 'oldPath', redirectTo: '/staticPath' },
{ path: ..., component: ..., data: { message: 'Custom' } }
]);
var routing = ng.router.RouterModule.forRoot(routes);`|`ng.router.Routes`
description:
Configures routes for the application. Supports static, parameterized, redirect, and wildcard routes. Also supports custom route data and resolve.
@cheatsheetItem
syntax:
`
<router-outlet></router-outlet>
<router-outlet name="aux"></router-outlet>
`|`router-outlet`
description:
Marks the location to load the component of the active route.
@cheatsheetItem
syntax:
`
<a routerLink="/path">
<a [routerLink]="[ '/path', routeParam ]">
<a [routerLink]="[ '/path', { matrixParam: 'value' } ]">
<a [routerLink]="[ '/path' ]" [queryParams]="{ page: 1 }">
<a [routerLink]="[ '/path' ]" fragment="anchor">
`|`[routerLink]`
description:
Creates a link to a different view based on a route instruction consisting of a route path, required and optional parameters, query parameters, and a fragment. To navigate to a root route, use the `/` prefix; for a child route, use the `./`prefix; for a sibling or parent, use the `../` prefix.
@cheatsheetItem
syntax:
`<a [routerLink]="[ '/path' ]" routerLinkActive="active">`
description:
The provided classes are added to the element when the `routerLink` becomes the current active route.
@cheatsheetItem
syntax(ts):
`class CanActivateGuard implements CanActivate {
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean>|Promise<boolean>|boolean { ... }
}
{ path: ..., canActivate: [CanActivateGuard] }`|`CanActivate`
syntax(js):
`var CanActivateGuard = ng.core.Class({
canActivate: function(route, state) {
// return Observable/Promise boolean or boolean
}
});
{ path: ..., canActivate: [CanActivateGuard] }`|`CanActivate`
description:
An interface for defining a class that the router should call first to determine if it should activate this component. Should return a boolean or an Observable/Promise that resolves to a boolean.
@cheatsheetItem
syntax(ts):
`class CanDeactivateGuard implements CanDeactivate<T> {
canDeactivate(
component: T,
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean>|Promise<boolean>|boolean { ... }
}
{ path: ..., canDeactivate: [CanDeactivateGuard] }`|`CanDeactivate`
syntax(js):
`var CanDeactivateGuard = ng.core.Class({
canDeactivate: function(component, route, state) {
// return Observable/Promise boolean or boolean
}
});
{ path: ..., canDeactivate: [CanDeactivateGuard] }`|`CanDeactivate`
description:
An interface for defining a class that the router should call first to determine if it should deactivate this component after a navigation. Should return a boolean or an Observable/Promise that resolves to a boolean.
@cheatsheetItem
syntax(ts):
`class CanActivateChildGuard implements CanActivateChild {
canActivateChild(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean>|Promise<boolean>|boolean { ... }
}
{ path: ..., canActivateChild: [CanActivateGuard],
children: ... }`|`CanActivateChild`
syntax(js):
`var CanActivateChildGuard = ng.core.Class({
canActivateChild: function(route, state) {
// return Observable/Promise boolean or boolean
}
});
{ path: ..., canActivateChild: [CanActivateChildGuard],
children: ... }`|`CanActivateChild`
description:
An interface for defining a class that the router should call first to determine if it should activate the child route. Should return a boolean or an Observable/Promise that resolves to a boolean.
@cheatsheetItem
syntax(ts):
`class ResolveGuard implements Resolve<T> {
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<any>|Promise<any>|any { ... }
}
{ path: ..., resolve: [ResolveGuard] }`|`Resolve`
syntax(js):
`var ResolveGuard = ng.core.Class({
resolve: function(route, state) {
// return Observable/Promise value or value
}
});
{ path: ..., resolve: [ResolveGuard] }`|`Resolve`
description:
An interface for defining a class that the router should call first to resolve route data before rendering the route. Should return a value or an Observable/Promise that resolves to a value.
@cheatsheetItem
syntax(ts):
`class CanLoadGuard implements CanLoad {
canLoad(
route: Route
): Observable<boolean>|Promise<boolean>|boolean { ... }
}
{ path: ..., canLoad: [CanLoadGuard], loadChildren: ... }`|`CanLoad`
syntax(js):
`var CanLoadGuard = ng.core.Class({
canLoad: function(route) {
// return Observable/Promise boolean or boolean
}
});
{ path: ..., canLoad: [CanLoadGuard], loadChildren: ... }`|`CanLoad`
description:
An interface for defining a class that the router should call first to check if the lazy loaded module should be loaded. Should return a boolean or an Observable/Promise that resolves to a boolean.

View File

@ -1,94 +0,0 @@
@cheatsheetSection
Template syntax
@cheatsheetIndex 2
@description
@cheatsheetItem
syntax:
`<input [value]="firstName">`|`[value]`
description:
Binds property `value` to the result of expression `firstName`.
@cheatsheetItem
syntax:
`<div [attr.role]="myAriaRole">`|`[attr.role]`
description:
Binds attribute `role` to the result of expression `myAriaRole`.
@cheatsheetItem
syntax:
`<div [class.extra-sparkle]="isDelightful">`|`[class.extra-sparkle]`
description:
Binds the presence of the CSS class `extra-sparkle` on the element to the truthiness of the expression `isDelightful`.
@cheatsheetItem
syntax:
`<div [style.width.px]="mySize">`|`[style.width.px]`
description:
Binds style property `width` to the result of expression `mySize` in pixels. Units are optional.
@cheatsheetItem
syntax:
`<button (click)="readRainbow($event)">`|`(click)`
description:
Calls method `readRainbow` when a click event is triggered on this button element (or its children) and passes in the event object.
@cheatsheetItem
syntax:
`<div title="Hello {{ponyName}}">`|`{{ponyName}}`
description:
Binds a property to an interpolated string, for example, "Hello Seabiscuit". Equivalent to:
`<div [title]="'Hello ' + ponyName">`
@cheatsheetItem
syntax:
`<p>Hello {{ponyName}}</p>`|`{{ponyName}}`
description:
Binds text content to an interpolated string, for example, "Hello Seabiscuit".
@cheatsheetItem
syntax:
`<my-cmp [(title)]="name">`|`[(title)]`
description:
Sets up two-way data binding. Equivalent to: `<my-cmp [title]="name" (titleChange)="name=$event">`
@cheatsheetItem
syntax:
`<video #movieplayer ...>
<button (click)="movieplayer.play()">
</video>`|`#movieplayer`|`(click)`
description:
Creates a local variable `movieplayer` that provides access to the `video` element instance in data-binding and event-binding expressions in the current template.
@cheatsheetItem
syntax:
`<p *myUnless="myExpression">...</p>`|`*myUnless`
description:
The `*` symbol turns the current element into an embedded template. Equivalent to:
`<ng-template [myUnless]="myExpression"><p>...</p></ng-template>`
@cheatsheetItem
syntax:
`<p>Card No.: {{cardNumber | myCardNumberFormatter}}</p>`|`{{cardNumber | myCardNumberFormatter}}`
description:
Transforms the current value of expression `cardNumber` via the pipe called `myCardNumberFormatter`.
@cheatsheetItem
syntax:
`<p>Employer: {{employer?.companyName}}</p>`|`{{employer?.companyName}}`
description:
The safe navigation operator (`?`) means that the `employer` field is optional and if `undefined`, the rest of the expression should be ignored.
@cheatsheetItem
syntax:
`<svg:rect x="0" y="0" width="100" height="100"/>`|`svg:`
description:
An SVG snippet template needs an `svg:` prefix on its root element to disambiguate the SVG element from an HTML component.
@cheatsheetItem
syntax:
`<svg>
<rect x="0" y="0" width="100" height="100"/>
</svg>`|`svg`
description:
An `<svg>` root element is detected as an SVG element automatically, without the prefix.

View File

@ -10,12 +10,41 @@ describe('site App', function() {
});
it('should show features text after clicking "Features"', () => {
page.featureLink.click().then(() => {
page.getLink('features').click().then(() => {
expect(page.getDocViewerText()).toMatch(/Progressive web apps/i);
});
});
it('should convert a doc with a code-example');
it('should show the tutorial index page at `/tutorial/`', () => {
// check that we can navigate directly to the tutorial page
page.navigateTo('tutorial/');
expect(page.getDocViewerText()).toMatch(/Tutorial: Tour of Heroes/i);
// navigate to a different page
page.getLink('features').click();
// check that we can navigate to the tutorial page via a link in the navigation
const heading = page.getNavHeading(/tutorial/i);
expect(heading.getText()).toMatch(/tutorial/i);
heading.click();
page.getLink('tutorial/').click();
expect(page.getDocViewerText()).toMatch(/Tutorial: Tour of Heroes/i);
});
it('should render `{@example}` dgeni tags as `<code-example>` elements with HTML escaped content', () => {
page.navigateTo('guide/component-styles');
const codeExample = element.all(by.css('code-example')).first();
expect(page.getInnerHtml(codeExample))
.toContain('@Component({\n selector: \'hero-app\',\n template: `\n &lt;h1&gt;Tour of Heroes&lt;/h1&gt;');
});
describe('api-docs', () => {
it('should show a link to github', () => {
page.navigateTo('api/common/NgClass');
expect(page.ghLink.getAttribute('href'))
.toMatch(/https:\/\/github.com\/angular\/angular\/tree\/.+\/packages\/common\/src\/directives\/ng_class\.ts/);
});
});
describe('google analytics', () => {
beforeEach(done => page.gaReady.then(done));

View File

@ -1,22 +1,39 @@
import { browser, element, by, promise } from 'protractor';
import { browser, element, by, promise, ElementFinder } from 'protractor';
const githubRegex = /https:\/\/github.com\/angular\/angular\//;
export class SitePage {
links = element.all(by.css('md-toolbar a'));
docViewer = element(by.css('aio-doc-viewer'));
codeExample = element.all(by.css('aio-doc-viewer pre > code'));
featureLink = element(by.css('md-toolbar a[href="features"]'));
ghLink = this.docViewer
.all(by.css('a'))
.filter((a: ElementFinder) => a.getAttribute('href').then(href => githubRegex.test(href)))
.first();
gaReady: promise.Promise<any>;
ga = () => browser.executeScript('return window["gaCalls"]') as promise.Promise<any[][]>;
locationPath = () => browser.executeScript('return document.location.pathname') as promise.Promise<string>;
getNavHeading(pattern: RegExp) {
return element.all(by.css('aio-nav-item a'))
.filter(element => element.getText().then(text => pattern.test(text)))
.first();
}
getLink(path) { return element(by.css(`a[href="${path}"]`)); }
ga() { return browser.executeScript('return window["gaCalls"]') as promise.Promise<any[][]>; }
locationPath() { return browser.executeScript('return document.location.pathname') as promise.Promise<string>; }
navigateTo() {
return browser.get('/').then(_ => this.replaceGa(_));
navigateTo(pageUrl = '') {
return browser.get('/' + pageUrl).then(_ => this.replaceGa(_));
}
getDocViewerText() {
return this.docViewer.getText();
}
getInnerHtml(element) {
// `getInnerHtml` was removed from webDriver and this is the workaround.
// See https://github.com/angular/protractor/blob/master/CHANGELOG.md#breaking-changes
return browser.executeScript('return arguments[0].innerHTML;', element);
}
/**
* Replace the ambient Google Analytics tracker with homebrew spy
* don't send commands to GA during e2e testing!

View File

@ -7,7 +7,7 @@
"cleanUrls": true,
"rewrites": [
{
"source": "**",
"source": "**/!(*.*)",
"destination": "/index.html"
}
]

View File

@ -12,15 +12,17 @@
"build": "yarn check-env && yarn docs && ng build -prod -sm",
"test": "yarn check-env && ng test --sourcemap=false",
"lint": "yarn check-env && ng lint",
"pree2e": "webdriver-manager update --standalone false --gecko false",
"pree2e": "yarn ~~update-webdriver",
"e2e": "yarn check-env && ng e2e --no-webdriver-update",
"deploy-preview": "scripts/deploy-preview.sh",
"deploy-staging": "firebase use staging --token \"$FIREBASE_TOKEN\" && yarn ~~deploy",
"pre~~deploy": "yarn build",
"~~deploy": "firebase deploy --message \"Commit: $TRAVIS_COMMIT\" --non-interactive --token \"$FIREBASE_TOKEN\"",
"check-env": "node ../tools/check-environment.js",
"predocs": "rimraf src/content",
"docs": "dgeni ./transforms/angular.io-package",
"docs-test": "node ../dist/tools/cjs-jasmine/index-tools ../../transforms/**/*.spec.js"
"docs-test": "node ../dist/tools/cjs-jasmine/index-tools ../../transforms/**/*.spec.js",
"~~update-webdriver": "webdriver-manager update --standalone false --gecko false",
"pre~~deploy": "yarn build",
"~~deploy": "firebase deploy --message \"Commit: $TRAVIS_COMMIT\" --non-interactive --token \"$FIREBASE_TOKEN\""
},
"private": true,
"dependencies": {
@ -35,21 +37,22 @@
"@angular/platform-browser-dynamic": "next",
"@angular/platform-server": "next",
"@angular/router": "next",
"@angular/service-worker": "^1.0.0-beta.6",
"@angular/service-worker": "^1.0.0-beta.7",
"core-js": "^2.4.1",
"rxjs": "^5.1.0",
"rho": "https://github.com/petebacondarwin/rho#heading-fix",
"rxjs": "^5.2.0",
"ts-helpers": "^1.1.1",
"zone.js": "0.7.8"
"zone.js": "^0.8.4"
},
"devDependencies": {
"@angular/cli": "^1.0.0-rc.0",
"@angular/cli": "^1.0.0-rc.4",
"@angular/compiler-cli": "next",
"@types/jasmine": "2.5.38",
"@types/node": "~6.0.60",
"canonical-path": "^0.0.2",
"codelyzer": "~2.0.0-beta.4",
"dgeni": "^0.4.7",
"dgeni-packages": "^0.16.8",
"dgeni-packages": "0.17.0",
"entities": "^1.1.1",
"firebase-tools": "^3.2.1",
"gulp": "^3.9.1",
@ -63,7 +66,7 @@
"karma-jasmine-html-reporter": "^0.2.2",
"lodash": "^4.17.4",
"protractor": "~5.1.0",
"rho": "^0.3.0",
"rimraf": "^2.6.1",
"ts-node": "~2.0.0",
"tslint": "~4.4.2",
"typescript": "2.1.6"

View File

@ -8,6 +8,7 @@
<md-sidenav-container class="sidenav-container">
<md-sidenav #sidenav class="sidenav" [opened]="isSideBySide" [mode] = "isSideBySide ? 'side' : 'over'">
<div class="version-info vertical-menu-item">{{ (versionInfo | async)?.full }}</div>
<aio-top-menu *ngIf="!isSideBySide" class="small" [nodes]="(navigationViews | async)?.TopBar" [homeImageUrl]="homeImageUrl"></aio-top-menu>
<aio-nav-menu [nodes]="(navigationViews | async)?.SideNav" [selectedNodes]="selectedNodes | async"></aio-nav-menu>
</md-sidenav>
@ -16,5 +17,4 @@
<aio-search-results #searchResults></aio-search-results>
<aio-doc-viewer [doc]="currentDocument | async" (docRendered)="onDocRendered($event)"></aio-doc-viewer>
</section>
</md-sidenav-container>

View File

@ -11,6 +11,8 @@ import { AutoScrollService } from 'app/shared/auto-scroll.service';
import { MockSearchService } from 'testing/search.service';
import { LocationService } from 'app/shared/location.service';
import { MockLocationService } from 'testing/location.service';
import { Logger } from 'app/shared/logger.service';
import { MockLogger } from 'testing/logger.service';
describe('AppComponent', () => {
let component: AppComponent;
@ -24,7 +26,8 @@ describe('AppComponent', () => {
{ provide: APP_BASE_HREF, useValue: '/' },
{ provide: SearchService, useClass: MockSearchService },
{ provide: GaService, useClass: TestGaService },
{ provide: LocationService, useFactory: () => new MockLocationService(initialUrl) }
{ provide: LocationService, useFactory: () => new MockLocationService(initialUrl) },
{ provide: Logger, useClass: MockLogger }
]
});
TestBed.compileComponents();

View File

@ -5,7 +5,7 @@ import { GaService } from 'app/shared/ga.service';
import { LocationService } from 'app/shared/location.service';
import { DocumentService, DocumentContents } from 'app/documents/document.service';
import { DocViewerComponent } from 'app/layout/doc-viewer/doc-viewer.component';
import { NavigationService, NavigationViews, NavigationNode } from 'app/navigation/navigation.service';
import { NavigationService, NavigationViews, NavigationNode, VersionInfo } from 'app/navigation/navigation.service';
import { SearchService } from 'app/search/search.service';
import { SearchResultsComponent } from 'app/search/search-results/search-results.component';
import { AutoScrollService } from 'app/shared/auto-scroll.service';
@ -24,6 +24,7 @@ export class AppComponent implements OnInit {
currentDocument: Observable<DocumentContents>;
navigationViews: Observable<NavigationViews>;
selectedNodes: Observable<NavigationNode[]>;
versionInfo: Observable<VersionInfo>;
@ViewChildren('searchBox, searchResults', { read: ElementRef })
searchElements: QueryList<ElementRef>;
@ -45,6 +46,7 @@ export class AppComponent implements OnInit {
locationService.currentUrl.subscribe(url => gaService.locationChanged(url));
this.navigationViews = navigationService.navigationViews;
this.selectedNodes = navigationService.selectedNodes;
this.versionInfo = navigationService.versionInfo;
}
ngOnInit() {

View File

@ -155,5 +155,12 @@ describe('DocumentService', () => {
expect(backend.connectionsArray[0].request.url).toEqual(CONTENT_URL_PREFIX + 'index.json');
});
it('should map the "folder" locations to the correct document request', () => {
const { service, backend, location } = getServices('guide/');
service.currentDocument.subscribe();
expect(backend.connectionsArray[0].request.url).toEqual(CONTENT_URL_PREFIX + 'guide.json');
});
});
});

View File

@ -63,8 +63,11 @@ export class DocumentService {
private computePath(url: string) {
url = url.match(/[^#?]*/)[0]; // strip off fragment and query
url = '/' + url;
url = url.endsWith('/') ? url + 'index' : url;
return 'content/docs' + url + '.json';
url = url.replace(/\/$/, ''); // strip off trailing slash
if (url === '') {
// deal with root url
url = 'index';
}
return 'content/docs/' + url + '.json';
}
}

View File

@ -17,6 +17,7 @@ export class NavItemComponent implements OnChanges {
ngOnChanges(changes: SimpleChanges) {
if (changes['selectedNodes'] || changes['node']) {
this.isSelected = this.selectedNodes.indexOf(this.node) !== -1;
this.isExpanded = this.isExpanded || this.isSelected;
}
this.setClasses();
}

View File

@ -1,7 +1,7 @@
import { ReflectiveInjector } from '@angular/core';
import { Http, ConnectionBackend, RequestOptions, BaseRequestOptions, Response, ResponseOptions } from '@angular/http';
import { MockBackend } from '@angular/http/testing';
import { NavigationService, NavigationViews, NavigationNode } from 'app/navigation/navigation.service';
import { NavigationService, NavigationViews, NavigationNode, VersionInfo } from 'app/navigation/navigation.service';
import { LocationService } from 'app/shared/location.service';
import { MockLocationService } from 'testing/location.service';
import { Logger } from 'app/shared/logger.service';
@ -125,4 +125,22 @@ describe('NavigationService', () => {
expect(currentNodes).toEqual([]);
});
});
describe('versionInfo', () => {
let service: NavigationService, versionInfo: VersionInfo;
beforeEach(() => {
service = injector.get(NavigationService);
service.versionInfo.subscribe(info => versionInfo = info);
const backend = injector.get(ConnectionBackend);
backend.connectionsArray[0].mockRespond(createResponse({
__versionInfo: { raw: '4.0.0' }
}));
});
it('should extract the version info', () => {
expect(versionInfo).toEqual({ raw: '4.0.0' });
});
});
});

View File

@ -12,28 +12,63 @@ import { LocationService } from 'app/shared/location.service';
import { NavigationNode } from './navigation-node';
export { NavigationNode } from './navigation-node';
export type NavigationResponse = {__versionInfo: VersionInfo } & { [name: string]: NavigationNode[]|VersionInfo };
export interface NavigationViews {
[name: string]: NavigationNode[];
}
export interface NavigationMap {
[url: string]: NavigationNode;
}
export interface VersionInfo {
raw: string;
major: number;
minor: number;
patch: number;
prerelease: string[];
build: string;
version: string;
codeName: string;
isSnapshot: boolean;
full: string;
branch: string;
commitSHA: string;
}
const navigationPath = 'content/navigation.json';
@Injectable()
export class NavigationService {
/**
* An observable collection of NavigationNode trees, which can be used to render navigational menus
*/
navigationViews = this.fetchNavigationViews();
navigationViews: Observable<NavigationViews>;
/**
* The current version of doc-app that we are running
*/
versionInfo: Observable<VersionInfo>;
/**
* An observable array of nodes that indicate which nodes in the `navigationViews` match the current URL location
*/
selectedNodes = this.getSelectedNodes();
selectedNodes: Observable<NavigationNode[]>;
constructor(private http: Http, private location: LocationService, private logger: Logger) { }
constructor(private http: Http, private location: LocationService, private logger: Logger) {
const navigationInfo = this.fetchNavigationInfo();
// The version information is packaged inside the navigation response to save us an extra request.
this.versionInfo = this.getVersionInfo(navigationInfo);
this.navigationViews = this.getNavigationViews(navigationInfo);
this.selectedNodes = this.getSelectedNodes(this.navigationViews);
}
/**
* Get an observable that fetches the `NavigationViews` from the server.
* Get an observable that fetches the `NavigationResponse` from the server.
* We create an observable by calling `http.get` but then publish it to share the result
* among multiple subscribers, without triggering new requests.
* We use `publishLast` because once the http request is complete the request observable completes.
@ -43,10 +78,22 @@ export class NavigationService {
* another request to the server.
* We are not storing the subscription from connecting as we do not expect this service to be destroyed.
*/
private fetchNavigationViews(): Observable<NavigationViews> {
const navigationViews = this.http.get(navigationPath)
.map(res => res.json() as NavigationViews)
private fetchNavigationInfo(): Observable<NavigationResponse> {
const navigationInfo = this.http.get(navigationPath)
.map(res => res.json() as NavigationResponse)
.publishLast();
navigationInfo.connect();
return navigationInfo;
}
private getVersionInfo(navigationInfo: Observable<NavigationResponse>) {
const versionInfo = navigationInfo.map(response => response.__versionInfo).publishReplay(1);
versionInfo.connect();
return versionInfo;
}
private getNavigationViews(navigationInfo: Observable<NavigationResponse>): Observable<NavigationViews> {
const navigationViews = navigationInfo.map(response => unpluck(response, '__versionInfo')).publishReplay(1);
navigationViews.connect();
return navigationViews;
}
@ -57,9 +104,9 @@ export class NavigationService {
* URL change before they receive an emission.
* See above for discussion of using `connect`.
*/
private getSelectedNodes() {
private getSelectedNodes(navigationViews: Observable<NavigationViews>) {
const selectedNodes = combineLatest(
this.navigationViews.map(this.computeUrlToNodesMap),
navigationViews.map(this.computeUrlToNodesMap),
this.location.currentUrl,
(navMap, url) => navMap[url] || [])
.publishReplay(1);
@ -74,7 +121,7 @@ export class NavigationService {
* @param navigation A collection of navigation nodes that are to be mapped
*/
private computeUrlToNodesMap(navigation: NavigationViews) {
const navMap = {};
const navMap: NavigationMap = {};
Object.keys(navigation).forEach(key => navigation[key].forEach(node => walkNodes(node)));
return navMap;
@ -90,3 +137,9 @@ export class NavigationService {
}
}
}
function unpluck(obj: any, property: string) {
const result = Object.assign({}, obj);
delete result[property];
return result;
}

View File

@ -21,7 +21,6 @@
sizes="16x16">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Lato:300,400" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Droid+Sans+Mono" rel="stylesheet">
<!-- Google Analytics -->

View File

@ -1,10 +1,8 @@
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();

View File

@ -1,7 +1,24 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
// This file includes polyfills needed by Angular and is loaded before the app.
// You can add your own extra polyfills to this file.
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
@ -15,24 +32,37 @@
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/set';
import 'reflect-metadata';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/** IE10 and IE11 requires the following to support `@angular/animation`. */
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
// If you need to support the browsers/features below, uncomment the import
// and run `npm install import-name-here';
// Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
/** Evergreen browsers require these. **/
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
// Needed for: IE9
// import 'classlist.js';
// Animations
// Needed for: All but Chrome and Firefox, Not supported in IE9
// import 'web-animations-js';
/** ALL Firefox browsers require the following to support `@angular/animation`. **/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
// Date, currency, decimal and percent pipes
// Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
// import 'intl';
// NgClass on SVG elements
// Needed for: IE10, IE11
// import 'classlist.js';
/***************************************************************************************************
* Zone JS is required by Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
/**
* Date, currency, decimal and percent pipes.
* Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
*/
// import 'intl'; // Run `npm install --save intl`.

View File

@ -68,7 +68,7 @@
font-size: 18px;
font-weight: 300;
color: white;
font-family: $support-font;
font-family: $main-font;
text-transform: uppercase;
}

View File

@ -131,8 +131,9 @@
}
.level-1 {
font-family: $support-font;
font-weight: 500;
font-family: $main-font;
font-size: 14px;
font-weight: 400;
text-transform: uppercase;
padding-left: 10px;
transition: background-color 0.2s;
@ -148,22 +149,12 @@
}
.level-3 {
font-family: $support-font;
font-family: $main-font;
font-size: 14px;
color: $mediumgray;
padding-left: 30px;
}
@mixin rotate($degrees) {
-moz-transform: rotate($degrees);
-webkit-transform: rotate($degrees);
-o-transform: rotate($degrees);
-ms-transform: rotate($degrees);
transform: rotate($degrees);
transition: transform 150ms;
transition-timing-function: ease-in-out;
}
.level-1.expanded .material-icons, .level-2.expanded .material-icons {
@include rotate(90deg);
}
@ -171,3 +162,7 @@
.level-1:not(.expanded) .material-icons, .level-2:not(.expanded) .material-icons {
@include rotate(0deg);
}
.version-info {
border: 3px $blue solid;
}

View File

@ -20,7 +20,9 @@ aio-top-menu li {
}
md-toolbar.mat-toolbar {
box-shadow: 6px 0 6px rgba(0,0,0,0.10);
position: relative;
z-index: 10;
box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.30);
padding: 0 16px 0px 0px;
}

View File

@ -2,7 +2,6 @@ $small-breakpoint-width: 840px;
// TYPOGRAPHY
$main-font: "Roboto","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;
$support-font: "Lato","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;
$code-font: "Droid Sans Mono", monospace;
// COLOR PALETTE

View File

@ -6,6 +6,7 @@
@import './constants';
// import global mixins
@import './mixins';
// import directories
@import './0-base/base-dir';

View File

@ -0,0 +1,9 @@
@mixin rotate($degrees) {
-moz-transform: rotate($degrees);
-webkit-transform: rotate($degrees);
-o-transform: rotate($degrees);
-ms-transform: rotate($degrees);
transform: rotate($degrees);
transition: transform 150ms;
transition-timing-function: ease-in-out;
}

View File

@ -1,6 +1,5 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone';
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';

View File

@ -16,7 +16,7 @@ const gitPackage = require('dgeni-packages/git');
const linksPackage = require('../links-package');
const examplesPackage = require('../examples-package');
const targetPackage = require('../target-package');
const cheatsheetPackage = require('../cheatsheet-package');
const contentPackage = require('../content-package');
const rhoPackage = require('../rho-package');
const PROJECT_ROOT = path.resolve(__dirname, '../../..');
@ -31,7 +31,7 @@ module.exports =
'angular.io',
[
jsdocPackage, nunjucksPackage, typescriptPackage, linksPackage, examplesPackage,
gitPackage, targetPackage, cheatsheetPackage, rhoPackage
gitPackage, targetPackage, contentPackage, rhoPackage
])
// Register the processors
@ -47,10 +47,16 @@ module.exports =
.processor(require('./processors/filterMemberDocs'))
.processor(require('./processors/convertToJson'))
.processor(require('./processors/markBarredODocsAsPrivate'))
.processor(require('./processors/filterPrivateDocs'))
.processor(require('./processors/filterIgnoredDocs'))
.processor(require('./processors/fixInternalDocumentLinks'))
.processor(require('./processors/processNavigationMap'))
// overrides base packageInfo and returns the one for the 'angular/angular' repo.
.factory('packageInfo', function() { return require(path.resolve(PROJECT_ROOT, 'package.json')); })
.factory(require('./readers/navigation'))
.config(function(checkAnchorLinksProcessor, log) {
// TODO: re-enable
checkAnchorLinksProcessor.$enabled = false;
@ -58,12 +64,13 @@ module.exports =
// Where do we get the source files?
.config(function(
readTypeScriptModules, readFilesProcessor, collectExamples, generateKeywordsProcessor) {
readTypeScriptModules, readFilesProcessor, collectExamples, generateKeywordsProcessor, navigationFileReader) {
// API files are typescript
readTypeScriptModules.basePath = API_SOURCE_PATH;
readTypeScriptModules.ignoreExportsMatching = [/^_/];
readTypeScriptModules.hidePrivateMembers = true;
readFilesProcessor.fileReaders.push(navigationFileReader)
readTypeScriptModules.sourceFiles = [
'common/index.ts',
'common/testing/index.ts',
@ -103,7 +110,6 @@ module.exports =
include: CONTENTS_PATH + '/file-not-found.md',
fileReader: 'contentFileReader'
},
{basePath: CONTENTS_PATH, include: CONTENTS_PATH + '/cheatsheet/*.md'},
{
basePath: API_SOURCE_PATH,
include: API_SOURCE_PATH + '/examples/**/*',
@ -112,8 +118,34 @@ module.exports =
{
basePath: CONTENTS_PATH,
include: CONTENTS_PATH + '/examples/**/*',
exclude: [
'**/*plnkr.no-link.html',
'**/node_modules/**',
// _boilerplate files
'**/_boilerplate/**',
'**/*/src/styles.css',
'**/*/src/systemjs-angular-loader.js',
'**/*/src/systemjs.config.js',
'**/*/src/tsconfig.json',
'**/*/bs-config.e2e.json',
'**/*/bs-config.json',
'**/*/package.json',
'**/*/tslint.json',
// example files
'**/_test-output',
'**/protractor-helpers.js',
'**/e2e-spec.js',
'**/ts/**/*.js',
'**/js-es6*/**/*.js',
'**/ts-snippets/**/*.js',
],
fileReader: 'exampleFileReader'
},
{
basePath: CONTENTS_PATH,
include: CONTENTS_PATH + '/navigation.json',
fileReader: 'navigationFileReader'
},
];
collectExamples.exampleFolders = ['examples', 'examples'];
@ -122,7 +154,12 @@ module.exports =
generateKeywordsProcessor.docTypesToIgnore = ['example-region'];
})
// Ignore certain problematic files
.config(function(filterIgnoredDocs) {
filterIgnoredDocs.ignore = [
/\/VERSION$/ // Ignore the `VERSION` const, since it would be written to the same file as the `Version` class
];
})
// Where do we write the output files?
.config(function(writeFilesProcessor) { writeFilesProcessor.outputFolder = OUTPUT_PATH; })
@ -228,13 +265,13 @@ module.exports =
pathTemplate: '${moduleDoc.moduleFolder}/${name}',
outputPathTemplate: '${moduleDoc.moduleFolder}/${name}.json',
},
{
docTypes: ['cheatsheet-data'],
pathTemplate: GUIDE_SEGMENT + '/cheatsheet.json',
outputPathTemplate: '${path}'
},
{docTypes: ['example-region'], getOutputPath: function() {}},
{docTypes: ['content'], pathTemplate: '${id}', outputPathTemplate: '${path}.json'}
{
docTypes: ['content'],
getPath: (doc) => `${doc.id.replace(/\/index$/, '')}`,
outputPathTemplate: '${path}.json'
},
{docTypes: ['navigation-map'], pathTemplate: '${id}', outputPathTemplate: '../${id}.json'}
];
})

View File

@ -0,0 +1,13 @@
/**
* Filter out docs whose id matches a pattern in the `filterIgnoredDocs.ignore` list
*/
module.exports = function filterIgnoredDocs() {
return {
ignore: [],
$runAfter: ['ids-computed'],
$runBefore: ['computing-paths'],
$process: function(docs) {
return docs.filter(doc => !this.ignore.some(regexp => regexp.test(doc.id)));
}
}
};

View File

@ -0,0 +1,39 @@
const testPackage = require('../../helpers/test-package');
const processorFactory = require('./filterIgnoredDocs');
const Dgeni = require('dgeni');
describe('filterIgnoredDocs processor', () => {
it('should be available on the injector', () => {
const dgeni = new Dgeni([testPackage('angular.io-package')]);
const injector = dgeni.configureInjector();
const processor = injector.get('filterIgnoredDocs');
expect(processor.$process).toBeDefined();
});
it('should run before the correct processor', () => {
const processor = processorFactory();
expect(processor.$runBefore).toEqual(['computing-paths'])
});
it('should run after the correct processor', () => {
const processor = processorFactory();
expect(processor.$runAfter).toEqual(['ids-computed']);
});
it('should remove docs that match the ignore list', () => {
const processor = processorFactory();
processor.ignore = [/\/VERSION$/, /ignore-me/];
const docs = [
{ id: 'public1'},
{ id: 'ignore-me/something' },
{ id: 'public2'},
{ id: 'and-me/VERSION' }
];
const filteredDocs = processor.$process(docs);
expect(filteredDocs).toEqual([
{ id: 'public1'},
{ id: 'public2'}
]);
})
});

View File

@ -0,0 +1,9 @@
module.exports = function filterPrivateDocs() {
return {
$runAfter: ['extra-docs-added'],
$runBefore: ['computing-paths'],
$process: function(docs) {
return docs.filter(function(doc) { return doc.privateExport !== true });
}
}
};

View File

@ -0,0 +1,40 @@
const testPackage = require('../../helpers/test-package');
const processorFactory = require('./filterPrivateDocs');
const Dgeni = require('dgeni');
describe('filterPrivateDocs processor', () => {
it('should be available on the injector', () => {
const dgeni = new Dgeni([testPackage('angular.io-package')]);
const injector = dgeni.configureInjector();
const processor = injector.get('filterPrivateDocs');
expect(processor.$process).toBeDefined();
});
it('should run before the correct processor', () => {
const processor = processorFactory();
expect(processor.$runBefore).toEqual(['computing-paths'])
});
it('should run after the correct processor', () => {
const processor = processorFactory();
expect(processor.$runAfter).toEqual(['extra-docs-added']);
});
it('should remove docs that are marked as private exports', () => {
const processor = processorFactory();
const docs = [
{ name: 'public1'},
{ name: 'ɵPrivate1', privateExport: true },
{ name: 'public2'},
{ name: 'ɵPrivate2', privateExport: true },
{ id: 'other'}
];
const filteredDocs = processor.$process(docs);
expect(filteredDocs).toEqual([
{ name: 'public1'},
{ name: 'public2'},
{ id: 'other'}
]);
})
});

View File

@ -0,0 +1,24 @@
/**
* @dgProcessor fixInternalDocumentLinks
* @description
* Add in the document path to links that start with a hash.
* This is important when the web app has a base href in place,
* since links like: `<a href="#some-id">` would get mapped to
* the URL `base/#some-id` even if the current location is `base/some/doc`.
*/
module.exports = function fixInternalDocumentLinks() {
var INTERNAL_LINK = /(<a [^>]*href=")(#[^"]*)/g;
return {
$runAfter: ['inlineTagProcessor'],
$runBefore: ['writeFilesProcessor'],
$process: function(docs) {
docs.forEach(doc => {
doc.renderedContent = doc.renderedContent.replace(INTERNAL_LINK, (_, pre, hash) => {
return pre + doc.path + hash;
});
});
}
};
};

View File

@ -0,0 +1,52 @@
const testPackage = require('../../helpers/test-package');
const processorFactory = require('./fixInternalDocumentLinks');
const Dgeni = require('dgeni');
describe('fixInternalDocumentLinks processor', () => {
it('should be available on the injector', () => {
const dgeni = new Dgeni([testPackage('angular.io-package')]);
const injector = dgeni.configureInjector();
const processor = injector.get('fixInternalDocumentLinks');
expect(processor.$process).toBeDefined();
});
it('should run before the correct processor', () => {
const processor = processorFactory();
expect(processor.$runBefore).toEqual(['writeFilesProcessor'])
});
it('should run after the correct processor', () => {
const processor = processorFactory();
expect(processor.$runAfter).toEqual(['inlineTagProcessor']);
});
it('should prefix internal hash links with the current doc path', () => {
const processor = processorFactory();
const docs = [
{
path: 'some/doc',
renderedContent: `
<a href="http://google.com#q=angular">Google</a>
<a href="some/relative/path#some-id">Some Id</a>
<a href="#some-internal-id">Link to heading</a>
<a class="important" href="#some-internal-id">Link to heading</a>
<a href="#some-internal-id" target="_blank">Link to heading</a>
`
},
];
processor.$process(docs);
expect(docs).toEqual([
{
path: 'some/doc',
renderedContent: `
<a href="http://google.com#q=angular">Google</a>
<a href="some/relative/path#some-id">Some Id</a>
<a href="some/doc#some-internal-id">Link to heading</a>
<a class="important" href="some/doc#some-internal-id">Link to heading</a>
<a href="some/doc#some-internal-id" target="_blank">Link to heading</a>
`
},
]);
})
});

View File

@ -11,12 +11,12 @@ describe('generateApiListDoc processor', () => {
expect(processor.$process).toBeDefined();
});
it('should run after "extra-docs-added"', () => {
it('should run after the correct processor', () => {
const processor = processorFactory();
expect(processor.$runAfter).toEqual(['extra-docs-added']);
});
it('should run before "rendering-docs"', () => {
it('should run before the correct processor', () => {
const processor = processorFactory();
expect(processor.$runBefore).toEqual(['rendering-docs']);
});

View File

@ -16,12 +16,12 @@ describe('generateKeywords processor', () => {
expect(processor.$process).toBeDefined();
});
it('should run after "paths-computed"', () => {
it('should run after the correct processor', () => {
const processor = processorFactory(mockLogger, mockReadFilesProcessor);
expect(processor.$runAfter).toEqual(['paths-computed']);
});
it('should run before "rendering-docs"', () => {
it('should run before the correct processor', () => {
const processor = processorFactory(mockLogger, mockReadFilesProcessor);
expect(processor.$runBefore).toEqual(['rendering-docs']);
});

View File

@ -0,0 +1,50 @@
module.exports = function processNavigationMap(versionInfo, log) {
return {
$runAfter: ['paths-computed'],
$runBefore: ['rendering-docs'],
$process: function(docs) {
const navigationDoc = docs.find(doc => doc.docType === 'navigation-map');
if (!navigationDoc) {
throw new Error(
'Missing navigation map document (docType="navigation-map").' +
'Did you forget to add it to the readFileProcessor?');
}
// Verify that all the navigation paths are to valid docs
const pathMap = {};
docs.forEach(doc => pathMap[doc.path] = true);
const errors = walk(navigationDoc.data, pathMap, []);
if (errors.length) {
log.error(`Navigation doc: ${navigationDoc.fileInfo.relativePath} contains invalid urls`);
console.log(errors);
// TODO(petebd): fail if there are errors: throw new Error('processNavigationMap failed');
}
// Add in the version data in a "secret" field to be extracted in the docs app
navigationDoc.data['__versionInfo'] = versionInfo.currentVersion;
}
}
};
function walk(node, map, path) {
let errors = [];
for(const key in node) {
const child = node[key];
if (key === 'url') {
const url = child.replace(/#.*$/, ''); // strip hash
if (isRelative(url) && !map[url]) {
errors.push({ path: path.join('.'), url });
}
} else if (typeof child !== 'string') {
errors = errors.concat(walk(child, map, path.concat([key])));
}
}
return errors;
}
function isRelative(url) {
return !/^(https?:)?\/\//.test(url);
}

View File

@ -0,0 +1,19 @@
/**
* Read in the navigation JSON
*/
module.exports = function navigationFileReader() {
return {
name: 'navigationFileReader',
getDocs: function(fileInfo) {
// We return a single element array because content files only contain one document
return [{
docType: 'navigation-map',
data: JSON.parse(fileInfo.content),
template: 'json-doc.template.json',
id: 'navigation',
aliases: ['navigation', 'navigation.json']
}];
}
};
};

View File

@ -1,16 +0,0 @@
var Package = require('dgeni').Package;
module.exports = new Package(
'cheatsheet',
[
require('../content-package'), require('../target-package'),
require('dgeni-packages/git'), require('dgeni-packages/nunjucks')
])
.factory(require('./services/cheatsheetItemParser'))
.processor(require('./processors/createCheatsheetDoc'))
.config(function(parseTagsProcessor, getInjectables) {
parseTagsProcessor.tagDefinitions = parseTagsProcessor.tagDefinitions.concat(
getInjectables(require('./tag-defs')));
});

View File

@ -1,48 +0,0 @@
var _ = require('lodash');
module.exports = function createCheatsheetDoc(
createDocMessage, renderMarkdown, versionInfo, targetEnvironments) {
return {
$runAfter: ['processing-docs'],
$runBefore: ['docs-processed'],
$process: function(docs) {
var currentEnvironment = targetEnvironments.isActive('ts') && 'TypeScript' ||
targetEnvironments.isActive('js') && 'JavaScript' ||
targetEnvironments.isActive('dart') && 'Dart';
var cheatsheetDoc = {
id: 'cheatsheet',
aliases: ['cheatsheet'],
docType: 'cheatsheet-data',
sections: [],
version: versionInfo,
currentEnvironment: currentEnvironment
};
docs = docs.filter(function(doc) {
if (doc.docType === 'cheatsheet-section') {
var section = _.pick(doc, ['name', 'description', 'items', 'index']);
// Let's make sure that the descriptions are rendered as markdown
section.description = renderMarkdown(section.description);
section.items.forEach(function(item) {
item.description = renderMarkdown(item.description);
});
cheatsheetDoc.sections.push(section);
return false;
}
return true;
});
// Sort the sections by their index
cheatsheetDoc.sections.sort(function(a, b) { return a.index - b.index; });
docs.push(cheatsheetDoc);
return docs;
}
};
};

View File

@ -1,125 +0,0 @@
/**
* @dgService
* @description
* Parse the text from a cheatsheetItem tag into a cheatsheet item object
* The text must contain a syntax block followed by zero or more bold matchers and finally a
* description
* The syntax block and bold matchers must be wrapped in backticks and be separated by pipes.
* For example
*
* ```
* `<div [ng-switch]="conditionExpression">
* <template [ng-switch-when]="case1Exp">...</template>
* <template ng-switch-when="case2LiteralString">...</template>
* <template ng-switch-default>...</template>
* </div>`|`[ng-switch]`|`[ng-switch-when]`|`ng-switch-when`|`ng-switch-default`
* Conditionally swaps the contents of the div by selecting one of the embedded templates based on
* the current value of conditionExpression.
* ```
*
* will be parsed into
*
* ```
* {
* syntax: '<div [ng-switch]="conditionExpression">\n'+
* ' <template [ng-switch-when]="case1Exp">...</template>\n'+
* ' <template ng-switch-when="case2LiteralString">...</template>\n'+
* ' <template ng-switch-default>...</template>\n'+
* '</div>',
* bold: ['[ng-switch]', '[ng-switch-when]', 'ng-switch-when', 'ng-switch-default'],
* description: 'Conditionally swaps the contents of the div by selecting one of the embedded
* templates based on the current value of conditionExpression.'
* }
* ```
*/
module.exports =
function cheatsheetItemParser(targetEnvironments) {
return function(text) {
var fields = getFields(text, ['syntax', 'description']);
var item = {syntax: '', bold: [], description: ''};
fields.forEach(function(field) {
if (!field.languages || targetEnvironments.someActive(field.languages)) {
switch (field.name) {
case 'syntax':
parseSyntax(field.value.trim());
break;
case 'description':
item.description = field.value.trim();
break;
}
}
});
return item;
function parseSyntax(text) {
var index = 0;
if (text.charAt(index) !== '`') throw new Error('item syntax must start with a backtick');
var start = index + 1;
index = text.indexOf('`', start);
if (index === -1) throw new Error('item syntax must end with a backtick');
item.syntax = text.substring(start, index);
start = index + 1;
// skip to next pipe
while (index < text.length && text.charAt(index) !== '|') index += 1;
while (text.charAt(start) === '|') {
start += 1;
// skip whitespace
while (start < text.length && /\s/.test(text.charAt(start))) start++;
if (text.charAt(start) !== '`') throw new Error('bold matcher must start with a backtick');
start += 1;
index = text.indexOf('`', start);
if (index === -1) throw new Error('bold matcher must end with a backtick');
item.bold.push(text.substring(start, index));
start = index + 1;
}
if (start !== text.length) {
throw new Error(
'syntax field must only contain a syntax code block and zero or more bold ' +
'matcher code blocks, delimited by pipes.\n' +
'Instead it was "' + text + '"');
}
}
};
}
function getFields(text, fieldNames) {
var FIELD_START = /^([^:(]+)\(?([^)]+)?\)?:$/;
var lines = text.split('\n');
var fields = [];
var field, line;
while (lines.length) {
line = lines.shift();
var match = FIELD_START.exec(line);
if (match && fieldNames.indexOf(match[1]) !== -1) {
// start new field
if (field) {
fields.push(field);
}
field = {name: match[1], languages: (match[2] && match[2].split(' ')), value: ''};
} else {
if (!field)
throw new Error(
'item must start with one of the following field specifiers:\n' +
fieldNames.map(function(field) { return field + ':'; }).join('\n') + '\n' +
'but instead it contained: "' + text + '"');
field.value += line + '\n';
}
}
if (field) {
fields.push(field);
}
return fields;
}

View File

@ -1,75 +0,0 @@
var testPackage = require('../../helpers/test-package');
var Dgeni = require('dgeni');
describe('cheatsheetItemParser', function() {
var dgeni, injector, cheatsheetItemParser;
beforeEach(function() {
dgeni = new Dgeni([testPackage('cheatsheet-package')]);
injector = dgeni.configureInjector();
cheatsheetItemParser = injector.get('cheatsheetItemParser');
var targetEnvironments = injector.get('targetEnvironments');
targetEnvironments.addAllowed('js');
targetEnvironments.addAllowed('ts', true);
});
describe('no language targets', function() {
it('should extract the syntax', function() {
expect(cheatsheetItemParser('syntax:\n`abc`'))
.toEqual({syntax: 'abc', bold: [], description: ''});
});
it('should extract the bolds', function() {
expect(cheatsheetItemParser('syntax:\n`abc`|`bold1`|`bold2`'))
.toEqual({syntax: 'abc', bold: ['bold1', 'bold2'], description: ''});
});
it('should extract the description', function() {
expect(cheatsheetItemParser('syntax:\n`abc`|`bold1`|`bold2`\ndescription:\nsome description'))
.toEqual({syntax: 'abc', bold: ['bold1', 'bold2'], description: 'some description'});
});
it('should allow bold to be optional', function() {
expect(cheatsheetItemParser('syntax:\n`abc`\ndescription:\nsome description'))
.toEqual({syntax: 'abc', bold: [], description: 'some description'});
});
it('should allow whitespace between the parts', function() {
expect(cheatsheetItemParser(
'syntax:\n`abc`| `bold1`| `bold2`\ndescription:\n\nsome description'))
.toEqual({syntax: 'abc', bold: ['bold1', 'bold2'], description: 'some description'});
});
});
describe('with language targets', function() {
it('should extract the active language', function() {
expect(cheatsheetItemParser(
'syntax(ts):\n`abc`|`bold1`|`bold2`\ndescription(ts):\nsome description'))
.toEqual({syntax: 'abc', bold: ['bold1', 'bold2'], description: 'some description'});
});
it('should ignore the non-active language', function() {
expect(cheatsheetItemParser(
'syntax(js):\n`abc`|`bold1`|`bold2`\ndescription(js):\nsome description'))
.toEqual({syntax: '', bold: [], description: ''});
});
it('should select the active language and ignore non-active language', function() {
expect(cheatsheetItemParser(
'syntax(js):\n`JS`|`boldJS``\n' +
'syntax(ts):\n`TS`|`boldTS`\n' +
'description(js):\nJS description\n' +
'description(ts):\nTS description'))
.toEqual({syntax: 'TS', bold: ['boldTS'], description: 'TS description'});
});
it('should error if a language target is used that is not allowed', function() {
expect(function() {
cheatsheetItemParser(
'syntax(dart):\n`abc`|`bold1`|`bold2`\ndescription(ts):\nsome description');
})
.toThrowError(
'Error accessing target "dart". It is not in the list of allowed targets: js,ts');
});
});
});

View File

@ -1,14 +0,0 @@
module.exports = function(createDocMessage) {
return {
name: 'cheatsheetIndex',
docProperty: 'index',
transforms: function(doc, tag, value) {
try {
return parseInt(value, 10);
} catch (x) {
throw new Error(
createDocMessage('"@' + tag.tagName + '" must be followed by a number', doc));
}
}
};
};

View File

@ -1,15 +0,0 @@
module.exports = function(createDocMessage, cheatsheetItemParser) {
return {
name: 'cheatsheetItem',
multi: true,
docProperty: 'items',
transforms: function(doc, tag, value) {
try {
return cheatsheetItemParser(value);
} catch (x) {
throw new Error(createDocMessage(
'"@' + tag.tagName + '" tag has an invalid format - ' + x.message, doc));
}
}
};
};

View File

@ -1,10 +0,0 @@
module.exports = function() {
return {
name: 'cheatsheetSection',
docProperty: 'docType',
transforms: function(doc, tag, value) {
doc.name = value ? value.trim() : '';
return 'cheatsheet-section';
}
};
};

View File

@ -1,2 +0,0 @@
module.exports =
[require('./cheatsheet-section'), require('./cheatsheet-index'), require('./cheatsheet-item')];

View File

@ -28,40 +28,48 @@ module.exports = function exampleInlineTagDef(
var unnamedArgs = tagArgs._;
var relativePath = unnamedArgs[0];
var regionName = tagArgs.region || (unnamedArgs.length > 1 ? unnamedArgs[1] : '');
var title = tagArgs.title || (unnamedArgs.length > 2 ? unnamedArgs[2] : null);
if (regionName === '\'\'') regionName = '';
var title = tagArgs.title || (unnamedArgs.length > 2 ? unnamedArgs.slice(2).join(' ') : null);
var linenums = tagArgs.linenums;
var stylePattern = tagArgs.stylePattern; // TODO: not yet implemented here
// Find the example in the folders
var exampleFile;
// Try an "annotated" version first
EXAMPLES_FOLDERS.some(
EXAMPLES_FOLDER => { return exampleFile = exampleMap[EXAMPLES_FOLDER][relativePath + '.annotated']; });
const sourceCode = getExampleRegion();
// If no annotated version is available then try the actual file
if (!exampleFile) {
EXAMPLES_FOLDERS.some(
EXAMPLES_FOLDER => { return exampleFile = exampleMap[EXAMPLES_FOLDER][relativePath]; });
const attributes = [];
if (title) attributes.push(` title="${title}"`);
if (linenums !== undefined) attributes.push(` linenums="${linenums}"`);
return '<code-example' + attributes.join('') + '>\n' + sourceCode + '\n</code-example>';
function getExampleRegion() {
// Find the example in the folders
var exampleFile;
// Try an "annotated" version first
EXAMPLES_FOLDERS.some(EXAMPLES_FOLDER => { return exampleFile = exampleMap[EXAMPLES_FOLDER][relativePath + '.annotated']; });
// If no annotated version is available then try the actual file
if (!exampleFile) {
EXAMPLES_FOLDERS.some(EXAMPLES_FOLDER => { return exampleFile = exampleMap[EXAMPLES_FOLDER][relativePath]; });
}
// If still no file then we error
if (!exampleFile) {
log.error(createDocMessage('Missing example file... relativePath: "' + relativePath + '".', doc));
log.error('Example files can be found in: ' + EXAMPLES_FOLDERS.join(', '));
return '';
}
var sourceCodeDoc = exampleFile.regions[regionName];
if (!sourceCodeDoc) {
log.error(createDocMessage('Missing example region... relativePath: "' + relativePath + '", region: "' + regionName + '".', doc));
log.error('Regions available are:', Object.keys[exampleFile.regions]);
return '';
}
return sourceCodeDoc.renderedContent;
}
// If still no file then we error
if (!exampleFile) {
log.error(
createDocMessage('Missing example file... relativePath: "' + relativePath + '".', doc));
log.error('Example files can be found in: ' + EXAMPLES_FOLDERS.join(', '));
return '';
}
var sourceCode = exampleFile.regions[regionName];
if (!sourceCode) {
log.error(createDocMessage(
'Missing example region... relativePath: "' + relativePath + '", region: "' +
regionName + '".',
doc));
log.error('Regions available are:', Object.keys[exampleFile.regions]);
return '';
}
return sourceCode.renderedContent;
}
};
};

View File

@ -0,0 +1,63 @@
var testPackage = require('../../helpers/test-package');
var Dgeni = require('dgeni');
describe('example inline-tag-def', function() {
let injector, tag, collectExamples, exampleMap;
beforeEach(() => {
const dgeni = new Dgeni([testPackage('examples-package', true)]);
injector = dgeni.configureInjector();
tag = injector.get('exampleInlineTagDef');
collectExamples = injector.get('collectExamples');
exampleMap = injector.get('exampleMap');
});
it('should be available as a service', () => {
expect(tag).toBeDefined();
expect(tag.name).toEqual('example');
});
describe('handler', () => {
let handler;
beforeEach(() => {
handler = tag.handler;
collectExamples.exampleFolders = ['examples'];
exampleMap['examples'] = {
'test/url': { regions: {
'': { renderedContent: 'whole file' },
'region-1': { renderedContent: 'region 1 contents' }
} }
};
});
it('should return a <code-example> tag', () => {
expect(handler({}, 'example', 'some/uri')).toEqual('<code-example>\n\n</code-example>');
});
it('should contain the whole contents from the example file if no region is specified', () => {
expect(handler({}, 'example', 'test/url')).toEqual('<code-example>\nwhole file\n</code-example>');
});
it('should contain the region contents from the example file if a region is specified', () => {
expect(handler({}, 'example', 'test/url region-1')).toEqual('<code-example>\nregion 1 contents\n</code-example>');
});
it('should add a title if specified', () => {
expect(handler({}, 'example', 'test/url region-1 \'Some Title\'')).toEqual('<code-example title="Some Title">\nregion 1 contents\n</code-example>');
expect(handler({}, 'example', 'test/url region-1 Some Title')).toEqual('<code-example title="Some Title">\nregion 1 contents\n</code-example>');
});
it('should contain the whole contents from the example file if an empty ("") region is specified', () => {
expect(handler({}, 'example', 'test/url \'\'')).toEqual('<code-example>\nwhole file\n</code-example>');
expect(handler({}, 'example', 'test/url \'\' Some Title')).toEqual('<code-example title="Some Title">\nwhole file\n</code-example>');
});
it('should add in linenum attribute if specified', () => {
expect(handler({}, 'example', 'test/url --linenums=\'false\'')).toEqual('<code-example linenums="false">\nwhole file\n</code-example>');
expect(handler({}, 'example', 'test/url --linenums=\'true\'')).toEqual('<code-example linenums="true">\nwhole file\n</code-example>');
expect(handler({}, 'example', 'test/url --linenums=\'15\'')).toEqual('<code-example linenums="15">\nwhole file\n</code-example>');
});
});
});

View File

@ -39,7 +39,10 @@ module.exports = function parseArgString() {
} else {
if (arg.substr(arg.length - 1) === '=') {
key = arg.substr(0, arg.length - 1);
// remove leading '-' if it exists.
// remove leading '-' (or '--') if it exists.
if (key.substr(0, 1) == '-') {
key = key.substr(1);
}
if (key.substr(0, 1) == '-') {
key = key.substr(1);
}

View File

@ -1,7 +1 @@
<div class="code-example">
{% marked %}
```
{$ doc.contents $}
```
{% endmarked %}
</div>
{$ doc.contents | escape $}

View File

@ -1,5 +1,5 @@
{% macro githubHref(doc, versionInfo) -%}
https://github.com/{$ versionInfo.gitRepoInfo.owner $}/{$ versionInfo.gitRepoInfo.repo $}/tree/{$ versionInfo.currentVersion.isSnapshot and versionInfo.currentVersion.SHA or versionInfo.currentVersion.raw $}/modules/{$ doc.fileInfo.projectRelativePath $}#L{$ doc.location.start.line+1 $}-L{$ doc.location.end.line+1 $}
https://github.com/{$ versionInfo.gitRepoInfo.owner $}/{$ versionInfo.gitRepoInfo.repo $}/tree/{$ versionInfo.currentVersion.isSnapshot and versionInfo.currentVersion.SHA or versionInfo.currentVersion.raw $}/packages/{$ doc.fileInfo.projectRelativePath $}#L{$ doc.location.start.line+1 $}-L{$ doc.location.end.line+1 $}
{%- endmacro %}
{% macro githubViewLink(doc, versionInfo) -%}

View File

@ -3,19 +3,15 @@
"@angular/animations@next":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-4.0.0-rc.2.tgz#b4818712cfb576e831cf9d108754463f00c111b9"
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-4.0.0-rc.6.tgz#a19d7512dd769102453c68b949d2478f69d3520f"
"@angular/cli@^1.0.0-rc.0":
version "1.0.0-rc.0"
resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-1.0.0-rc.0.tgz#dcf9e1d1f4ed886ca59de30a67fcc5ac98a2b061"
"@angular/cli@^1.0.0-rc.4":
version "1.0.0-rc.4"
resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-1.0.0-rc.4.tgz#e542f95378fd996fb0bc3b9d686bf3a457fe61b4"
dependencies:
"@angular/compiler" ">=2.3.1 <5.0.0 || >=4.0.0-beta <5.0.0"
"@angular/compiler-cli" ">=2.3.1 <5.0.0 || >=4.0.0-beta <5.0.0"
"@angular/core" ">=2.3.1 <5.0.0 || >=4.0.0-beta <5.0.0"
"@angular/tsc-wrapped" ">=0.5.0 <5.0.0 || >=4.0.0-beta <5.0.0"
"@ngtools/json-schema" "1.0.5"
"@ngtools/webpack" "1.2.11"
"@ngtools/webpack" "1.2.14"
autoprefixer "^6.5.3"
chalk "^1.1.3"
common-tags "^1.3.1"
@ -45,7 +41,6 @@
lodash "^4.11.1"
minimatch "^3.0.3"
node-modules-path "^1.0.0"
node-sass "^4.3.0"
nopt "^4.0.1"
opn "4.0.2"
portfinder "~1.0.12"
@ -72,68 +67,70 @@
webpack-dev-server "~2.3.0"
webpack-merge "^2.4.0"
zone.js "^0.7.2"
optionalDependencies:
node-sass "^4.3.0"
"@angular/common@next":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/common/-/common-4.0.0-rc.2.tgz#69f68639270d71b2e8c552e4fa939975fcb88304"
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/common/-/common-4.0.0-rc.6.tgz#f6855c36e1c8e1b7ce94c0739a1fa277a9d29584"
"@angular/compiler-cli@>=2.3.1 <5.0.0 || >=4.0.0-beta <5.0.0", "@angular/compiler-cli@next":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-4.0.0-rc.2.tgz#49730cb232d48aba25d68541eb9166bf5330dd2b"
"@angular/compiler-cli@next":
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-4.0.0-rc.6.tgz#3d4ed77ea7a37703d1f5bb974619509885f1084b"
dependencies:
"@angular/tsc-wrapped" "4.0.0-rc.2"
"@angular/tsc-wrapped" "4.0.0-rc.6"
minimist "^1.2.0"
reflect-metadata "^0.1.2"
"@angular/compiler@>=2.3.1 <5.0.0 || >=4.0.0-beta <5.0.0", "@angular/compiler@next":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-4.0.0-rc.2.tgz#643e199e6792413f42cf149a9cf1672284787c11"
"@angular/compiler@next":
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-4.0.0-rc.6.tgz#b46cd4c0c732eafac5a8658ca2d5d9b953906e99"
"@angular/core@>=2.3.1 <5.0.0 || >=4.0.0-beta <5.0.0", "@angular/core@next":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/core/-/core-4.0.0-rc.2.tgz#59535050e5d0e6141417186eee571296f8e9c3d0"
"@angular/core@next":
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/core/-/core-4.0.0-rc.6.tgz#ba70534bd45f3bda3ac39fb0a90d552510436dec"
"@angular/forms@next":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-4.0.0-rc.2.tgz#6d9df97783b6023d652d97369db13d6ad6c7fa9e"
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-4.0.0-rc.6.tgz#b075ca2bf0f0a37c84d1dcb67ac59ae334c1a392"
"@angular/http@next":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/http/-/http-4.0.0-rc.2.tgz#145ecd17f483b97e7750bb9e00b60e48ff82b67a"
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/http/-/http-4.0.0-rc.6.tgz#ebeb95a92725d6481b418b4a7beafd9281cc0e5c"
"@angular/material@https://github.com/angular/material2-builds":
version "2.0.0-beta.2"
resolved "https://github.com/angular/material2-builds#d7f549850cfd94b31bb624e2702b61305fd6337d"
"@angular/platform-browser-dynamic@next":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.0.0-rc.2.tgz#f2bbab322706dc6361d46647e1e2b7c26f036a1c"
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.0.0-rc.6.tgz#89dfce31283fb3fc1b484ffa620cd2b5f292ecdd"
"@angular/platform-browser@next":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-4.0.0-rc.2.tgz#bcca05ce85d320ee0b257640f15479b59fed20f0"
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-4.0.0-rc.6.tgz#bce3be3ee8a62b91a591f4b3cb894a1bc39c6da7"
"@angular/platform-server@next":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-4.0.0-rc.2.tgz#3b09f4e2f2dc1b7d723fbbdc6b99117019c0f9de"
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-4.0.0-rc.6.tgz#89bbbae2806252a350b46e18e0d8933618370e47"
dependencies:
parse5 "^3.0.1"
xhr2 "^0.1.4"
"@angular/router@next":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/router/-/router-4.0.0-rc.2.tgz#66fc5be012caa38441314d0a0b9c9b6a723c471a"
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/router/-/router-4.0.0-rc.6.tgz#3a02bb095f73e9db180576f38c73ab2a3a5bf0a0"
"@angular/service-worker@^1.0.0-beta.6":
version "1.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@angular/service-worker/-/service-worker-1.0.0-beta.6.tgz#ae3ca0b43ab1cbd572a191b2ef3e1b787f71ed1e"
"@angular/service-worker@^1.0.0-beta.7":
version "1.0.0-beta.7"
resolved "https://registry.yarnpkg.com/@angular/service-worker/-/service-worker-1.0.0-beta.7.tgz#e8edd2e993948caffc2d45d6935667f9b5a3c221"
dependencies:
base64-js "^1.1.2"
jshashes "^1.0.5"
"@angular/tsc-wrapped@4.0.0-rc.2", "@angular/tsc-wrapped@>=0.5.0 <5.0.0 || >=4.0.0-beta <5.0.0":
version "4.0.0-rc.2"
resolved "https://registry.yarnpkg.com/@angular/tsc-wrapped/-/tsc-wrapped-4.0.0-rc.2.tgz#d7023d93f4576b6f776ffc7175ff760e7e133705"
"@angular/tsc-wrapped@4.0.0-rc.6":
version "4.0.0-rc.6"
resolved "https://registry.yarnpkg.com/@angular/tsc-wrapped/-/tsc-wrapped-4.0.0-rc.6.tgz#95a82148ece7d3ebd9606e9fba2cb7758e3ea8ae"
dependencies:
tsickle "^0.21.0"
@ -141,12 +138,12 @@
version "1.0.5"
resolved "https://registry.yarnpkg.com/@ngtools/json-schema/-/json-schema-1.0.5.tgz#ad39037c70c88b245ac7267a71777646b6063d77"
"@ngtools/webpack@1.2.11":
version "1.2.11"
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-1.2.11.tgz#b587b1e7eb88bd68b973681669c00e7b4b7f8ea0"
"@ngtools/webpack@1.2.14":
version "1.2.14"
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-1.2.14.tgz#ff59f504196871e69b5d01a21ea747d6f8e5e546"
dependencies:
enhanced-resolve "^3.1.0"
loader-utils "^0.2.16"
loader-utils "^1.0.2"
magic-string "^0.19.0"
source-map "^0.5.6"
@ -1559,9 +1556,9 @@ detect-indent@^4.0.0:
dependencies:
repeating "^2.0.0"
dgeni-packages@^0.16.8:
version "0.16.8"
resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.16.8.tgz#e0596f1902ef76799576bed7bcc1d69943f853a3"
dgeni-packages@0.17.0:
version "0.17.0"
resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.17.0.tgz#b2e5117670e99109f664703af26a460a5064d6cc"
dependencies:
canonical-path "0.0.2"
catharsis "^0.8.1"
@ -5308,9 +5305,9 @@ restore-cursor@^2.0.0:
onetime "^2.0.0"
signal-exit "^3.0.2"
rho@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/rho/-/rho-0.3.0.tgz#a7ac95df240141936d1bf9d8f8e4880588c73dd3"
"rho@https://github.com/petebacondarwin/rho#heading-fix":
version "0.4.0"
resolved "https://github.com/petebacondarwin/rho#dcc9780a59d6bf6a62abe2fca4b08db6629da2ca"
dependencies:
html "*"
nomnom "*"
@ -5327,6 +5324,12 @@ rimraf@2, rimraf@^2.2.8, rimraf@^2.3.3, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.
dependencies:
glob "^7.0.5"
rimraf@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
dependencies:
glob "^7.0.5"
rimraf@~2.2.6:
version "2.2.8"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
@ -5377,7 +5380,7 @@ rx@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
rxjs@^5.0.1, rxjs@^5.1.0:
rxjs@^5.0.1, rxjs@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.2.0.tgz#db537de8767c05fa73721587a29e0085307d318b"
dependencies:
@ -5547,8 +5550,8 @@ sha.js@^2.3.6:
inherits "^2.0.1"
shelljs@^0.7.0:
version "0.7.6"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.6.tgz#379cccfb56b91c8601e4793356eb5382924de9ad"
version "0.7.7"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.7.tgz#b2f5c77ef97148f4b4f6e22682e10bba8667cff1"
dependencies:
glob "^7.0.0"
interpret "^1.0.0"
@ -6228,14 +6231,10 @@ underscore-contrib@~0.3.0:
dependencies:
underscore "1.6.0"
underscore@1.6.0, underscore@~1.6.0:
underscore@1.6.0, underscore@1.x, underscore@~1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8"
underscore@1.x:
version "1.8.3"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022"
uniq@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
@ -6835,10 +6834,10 @@ zip-stream@~0.6.0:
lodash "~3.10.1"
readable-stream "~1.0.26"
zone.js@0.7.8:
zone.js@^0.7.2:
version "0.7.8"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.8.tgz#4f3fe8834d44597f2639053a0fa438df34fffded"
zone.js@^0.7.2:
version "0.7.7"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.7.tgz#0d7b7ae7f68012d03438b8a18f5763441bbf9620"
zone.js@^0.8.4:
version "0.8.4"
resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.4.tgz#cc40ae5a1c879601c5ebba2096b5c80f0c4c3602"

View File

@ -12,9 +12,9 @@ PACKAGES=(core
compiler
common
animations
forms
platform-browser
platform-browser-dynamic
forms
http
platform-server
platform-webworker
@ -267,7 +267,7 @@ compilePackage() {
$NGC -p ${1}/tsconfig-build.json
echo "====== Create ${1}/../${package_name}.d.ts re-export file for Closure"
echo "$(cat ${LICENSE_BANNER}) ${N} export * from './${package_name}/index'" > ${2}/../${package_name}.d.ts
echo "{\"alias\": \"./${package_name}/index.metadata.json\"}" > ${2}/../${package_name}.metadata.json
echo "{\"__symbolic\":\"module\",\"version\":3,\"metadata\":{},\"exports\":[{\"from\":\"./${package_name}/index\"}]}" > ${2}/../${package_name}.metadata.json
fi
for DIR in ${1}/* ; do
@ -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

@ -32,7 +32,7 @@ We explicitly don't consider the following to be our public API surface:
- any file/import paths within our package except for the `/`, `/testing` and `/bundles/*`
- constructors of injectable classes (services and directives) - please use DI to obtain instances of these classes
- any class members or symbols marked as `private` or prefixed with underscore
- any class members or symbols marked as `private`, or prefixed with underscore (`_`) and [barred latin o](https://en.wikipedia.org/wiki/%C6%9F) (`ɵ`)
- extending any of our classes unless the support for this is specifically documented in the API docs
- the contents and API surface of the code generated by Angular's compiler (with one notable exception: the existence and name of `NgModuleFactory` instances exported from generated code is guaranteed)

View File

@ -63,6 +63,7 @@ Week Of | Stable Release<br>(@latest npm tag) | Beta/RC Release<br>(@n
2017-03-01 | 2.4.9 | 4.0.0-rc.2 |
2017-03-08 | 2.4.10 | 4.0.0-rc.3 |
2017-03-15 | 2.4.11 | 4.0.0-rc.4 |
*2017-03-17* | | *4.0.0-rc.5* | *Unplanned release to fix compiler-cli dependency version*
2017-03-22 | 4.0.0 + 2.4.12 | - | Major Version Release

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

@ -3,6 +3,7 @@
"version": "0.0.0",
"license": "MIT",
"dependencies": {
"@angular/animations": "file:../../dist/packages-dist/animations",
"@angular/common": "file:../../dist/packages-dist/common",
"@angular/compiler": "file:../../dist/packages-dist/compiler",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",

View File

@ -7,7 +7,8 @@
"compilerOptions": {
"module": "es2015",
"moduleResolution": "node",
"strictNullChecks": true,
// TODO(i): strictNullChecks should turned on but are temporarily disabled due to #15432
"strictNullChecks": false,
"target": "es6",
"noImplicitAny": false,
"sourceMap": false,

View File

@ -0,0 +1,3 @@
**/*.js
**/*.js.map
!src/systemjs.config.js

View File

@ -0,0 +1,14 @@
{
"open": false,
"logLevel": "silent",
"port": 8000,
"server": {
"baseDir": "src",
"routes": {
"/node_modules": "node_modules"
},
"middleware": {
"0": null
}
}
}

View File

@ -0,0 +1,8 @@
import { browser, element, by } from 'protractor';
describe('Hello world E2E Tests', function () {
it('should display: Hello world!', function () {
browser.get('');
expect(element(by.css('div')).getText()).toEqual('Hello world!');
});
});

View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"sourceMap": true,
"lib": [ "es2015", "dom" ],
"noImplicitAny": true,
"skipLibCheck": true,
"types": [
"jasmine"
]
}
}

View File

@ -0,0 +1,31 @@
{
"name": "angular-integration",
"description": "Ensure SystemJS ^0.22 UMD compatibility via __esModule flag.",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"test": "concurrently \"npm run serve\" \"npm run protractor\" --kill-others --success first",
"serve": "lite-server -c bs-config.e2e.json",
"preprotractor": "tsc -p e2e",
"protractor": "protractor protractor.config.js"
},
"dependencies": {
"@angular/common": "file:../../dist/packages-dist/common",
"@angular/core": "file:../../dist/packages-dist/core",
"@angular/compiler": "file:../../dist/packages-dist/compiler",
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
"@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic",
"core-js": "2.4.1",
"plugin-typescript": "6.0.4",
"rxjs": "file:../../node_modules/rxjs",
"systemjs": "0.20.2",
"typescript": "2.1.6",
"zone.js": "0.7.6"
},
"devDependencies": {
"@types/jasmine": "2.5.41",
"concurrently": "3.1.0",
"lite-server": "2.2.2",
"protractor": "file:../../node_modules/protractor"
}
}

View File

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

View File

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

View File

@ -0,0 +1,10 @@
import {Component, Injectable} from '@angular/core';
@Component({
selector: 'hello-world-app',
template: '<div>Hello {{ name }}!</div>',
})
@Injectable()
export class HelloWorldComponent {
name: string = 'world';
}

View File

@ -0,0 +1,21 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Hello World</title>
<base href="/">
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('main.ts').catch(function (err) { console.error(err); });
</script>
</head>
<body>
<hello-world-app>Loading...</hello-world-app>
</body>
</html>

View File

@ -0,0 +1,4 @@
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app/app';
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -0,0 +1,45 @@
(function (global) {
SystemJS.typescriptOptions = {
"target": "es5",
"module": "system",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
};
System.config({
transpiler: 'ts',
meta: {
'typescript': {
"exports": "ts"
}
},
paths: {
'npm:': 'node_modules/'
},
map: {
app: 'app',
'@angular/core': 'npm:@angular/core/bundles/core.umd.min.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.min.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.min.js',
'@angular/platform-browser':
'npm:@angular/platform-browser/bundles/platform-browser.umd.min.js',
'@angular/platform-browser-dynamic':
'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.min.js',
'rxjs': 'npm:rxjs',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'ts': 'npm:plugin-typescript/lib/plugin.js',
'typescript': 'npm:typescript/lib/typescript.js',
},
packages: {
app: {
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
}
}
});
})(this);

View File

@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "es5",
"module": "system",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [ "es2015", "dom" ],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
}
}

View File

@ -4,6 +4,7 @@
"license": "MIT",
"decription": "Angular Langauge Service plugin integration test",
"dependencies": {
"@angular/animations": "file:../../dist/packages-dist/animations",
"@angular/common": "file:../../dist/packages-dist/common",
"@angular/compiler": "file:../../dist/packages-dist/compiler",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",

View File

@ -4,6 +4,7 @@
"version": "0.0.0",
"license": "MIT",
"dependencies": {
"@angular/animations": "file:../../dist/packages-dist/animations",
"@angular/common": "file:../../dist/packages-dist/common",
"@angular/compiler": "file:../../dist/packages-dist/compiler",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",

View File

@ -9,7 +9,8 @@
"target": "es5",
"lib": ["es5", "dom", "es2015.collection", "es2015.iterable", "es2015.promise"],
"types": [],
"strictNullChecks": true
// TODO(i): strictNullChecks should turned on but are temporarily disabled due to #15432
"strictNullChecks": false
},
"files": [
"include-all.ts",

View File

@ -4,6 +4,7 @@
"version": "0.0.0",
"license": "MIT",
"dependencies": {
"@angular/animations": "file:../../dist/packages-dist/animations",
"@angular/common": "file:../../dist/packages-dist/common",
"@angular/compiler": "file:../../dist/packages-dist/compiler",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",

View File

@ -15,7 +15,8 @@
"es2015.promise"
],
"types": [],
"strictNullChecks": true
// TODO(i): strictNullChecks should turned on but are temporarily disabled due to #15432
"strictNullChecks": false
},
"files": [
"include-all.ts",

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>

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