Compare commits

..

64 Commits

Author SHA1 Message Date
f2f5286020 build: upgrade to latest bazel rules (#18733)
PR Close #18733
2017-08-23 11:34:52 -05:00
47220997e1 build: add bazel integration test (#18733)
It includes sass compilation, and building the bazel package
distribution.

PR Close #18733
2017-08-23 11:34:52 -05:00
9ffa490d3f refactor(compiler-cli): move ngc-wrapped to packages/bazel (#18733)
See design: https://goo.gl/rAeYWx

PR Close #18733
2017-08-23 11:34:51 -05:00
a80ecf6a77 Revert "refactor(router): remove deprecated initialNavigation options (#18781)"
This reverts commit d76761bf01.
2017-08-22 18:39:06 -05:00
7236095f6f Revert "refactor(router): remove deprecated RouterOutlet properties (#18781)"
This reverts commit d1c4a94bbf.
2017-08-22 18:38:53 -05:00
d1c4a94bbf refactor(router): remove deprecated RouterOutlet properties (#18781)
BREAKING CHANGE: `RouterOutlet` properties `locationInjector` and `locationFactoryResolver` have been removed as they were deprecated since v4.

PR Close #18781
2017-08-22 16:53:00 -05:00
d76761bf01 refactor(router): remove deprecated initialNavigation options (#18781)
BREAKING CHANGE: the values `true`, `false`, `legacy_enabled` and `legacy_disabled` for the router parameter `initialNavigation` have been removed as they were deprecated. Use `enabled` or `disabled` instead.

PR Close #18781
2017-08-22 16:53:00 -05:00
c055dc7441 docs(aio): add info about --local option in the readme (#18824)
PR Close #18824
2017-08-22 15:56:12 -05:00
3dc4115c8b docs(aio): fix "Error handling" section in "HttpClient" (#18821)
Removed additional curly brackets to fix blocks. Also replaced tab with 2 spaces.

PR Close #18821
2017-08-22 15:56:12 -05:00
1f1caacbfd refactor(platform-browser-dynamic): keep preserveWhitespaces default setting in one place (#18772)
CompilerConfig should be the only source of default settings for preserveWhitespaces
so let's not enforce defaults on the CompilerOptions level.

PR Close #18772
2017-08-22 15:56:12 -05:00
713d7c2360 fix(core): make sure onStable runs in the right zone (#18706)
Make sure the callbacks to the NgZone callbacks run in the right zone
with or without the rxjs Zone patch -
1ed83d08ac.

PR Close #18706
2017-08-22 15:56:12 -05:00
079d884b6c feat(common): drop use of the Intl API to improve browser support (#18284)
BREAKING CHANGE: Because of multiple bugs and browser inconsistencies, we have dropped the intl api in favor of data exported from the Unicode Common Locale Data Repository (CLDR).
Unfortunately we had to change the i18n pipes (date, number, currency, percent) and there are some breaking changes.

1. I18n pipes
* Breaking change:
  - By default Angular now only contains locale data for the language `en-US`, if you set the value of `LOCALE_ID` to another locale, you will have to import new locale data for this language because we don't use the intl API anymore.

* Features:
  - you don't need to use the intl polyfill for Angular anymore.
  - all i18n pipes now have an additional last parameter `locale` which allows you to use a specific locale instead of the one defined in the token `LOCALE_ID` (whose value is `en-US` by default).
  - the new locale data extracted from CLDR are now available to developers as well and can be used through an API (which should be especially useful for library authors).
  - you can still use the old pipes for now, but their names have been changed and they are no longer included in the `CommonModule`. To use them, you will have to import the `DeprecatedI18NPipesModule` after the `CommonModule` (the order is important):

  ```ts
  import { NgModule } from '@angular/core';
  import { CommonModule, DeprecatedI18NPipesModule } from '@angular/common';

  @NgModule({
    imports: [
      CommonModule,
      // import deprecated module after
      DeprecatedI18NPipesModule
    ]
  })
  export class AppModule { }
  ```

  Dont forget that you will still need to import the intl API polyfill if you want to use those deprecated pipes.

2. Date pipe
* Breaking changes:
  - the predefined formats (`short`, `shortTime`, `shortDate`, `medium`, ...) now use the patterns given by CLDR (like it was in AngularJS) instead of the ones from the intl API. You might notice some changes, e.g. `shortDate` will be `8/15/17` instead of `8/15/2017` for `en-US`.
  - the narrow version of eras is now `GGGGG` instead of `G`, the format `G` is now similar to `GG` and `GGG`.
  - the narrow version of months is now `MMMMM` instead of `L`, the format `L` is now the short standalone version of months.
  - the narrow version of the week day is now `EEEEE` instead of `E`, the format `E` is now similar to `EE` and `EEE`.
  - the timezone `z` will now fallback to `O` and output `GMT+1` instead of the complete zone name (e.g. `Pacific Standard Time`), this is because the quantity of data required to have all the zone names in all of the existing locales is too big.
  - the timezone `Z` will now output the ISO8601 basic format, e.g. `+0100`, you should now use `ZZZZ` to get `GMT+01:00`.

  | Field type | Format        | Example value         | v4 | v5            |
  |------------|---------------|-----------------------|----|---------------|
  | Eras       | Narrow        | A for AD              | G  | GGGGG         |
  | Months     | Narrow        | S for September       | L  | MMMMM         |
  | Week day   | Narrow        | M for Monday          | E  | EEEEE         |
  | Timezone   | Long location | Pacific Standard Time | z  | Not available |
  | Timezone   | Long GMT      | GMT+01:00             | Z  | ZZZZ          |

* Features
  - new predefined formats `long`, `full`, `longTime`, `fullTime`.
  - the format `yyy` is now supported, e.g. the year `52` will be `052` and the year `2017` will be `2017`.
  - standalone months are now supported with the formats `L` to `LLLLL`.
  - week of the year is now supported with the formats `w` and `ww`, e.g. weeks `5` and `05`.
  - week of the month is now supported with the format `W`, e.g. week `3`.
  - fractional seconds are now supported with the format `S` to `SSS`.
  - day periods for AM/PM now supports additional formats `aa`, `aaa`, `aaaa` and `aaaaa`. The formats `a` to `aaa` are similar, while `aaaa` is the wide version if available (e.g. `ante meridiem` for `am`), or equivalent to `a` otherwise, and `aaaaa` is the narrow version (e.g. `a` for `am`).
  - extra day periods are now supported with the formats `b` to `bbbbb` (and `B` to `BBBBB` for the standalone equivalents), e.g. `morning`, `noon`, `afternoon`, ....
  - the short non-localized timezones are now available with the format `O` to `OOOO`. The formats `O` to `OOO` will output `GMT+1` while the format `OOOO` will be `GMT+01:00`.
  - the ISO8601 basic time zones are now available with the formats `Z` to `ZZZZZ`. The formats `Z` to `ZZZ` will output `+0100`, while the format `ZZZZ` will be `GMT+01:00` and `ZZZZZ` will be `+01:00`.

* Bug fixes
  - the date pipe will now work exactly the same across all browsers, which will fix a lot of bugs for safari and IE.
  - eras can now be used on their own without the date, e.g. the format `GG` will be `AD` instead of `8 15, 2017 AD`.

3. Currency pipe
* Breaking change:
  - the default value for `symbolDisplay` is now `symbol` instead of `code`. This means that by default you will see `$4.99` for `en-US` instead of `USD4.99` previously.

* Deprecation:
  - the second parameter of the currency pipe (`symbolDisplay`) is no longer a boolean, it now takes the values `code`, `symbol` or `symbol-narrow`. A boolean value is still valid for now, but it is deprecated and it will print a warning message in the console.

* Features:
  - you can now choose between `code`, `symbol` or `symbol-narrow` which gives you access to more options for some currencies (e.g. the canadian dollar with the code `CAD` has the symbol `CA$` and the symbol-narrow `$`).

4. Percent pipe
* Breaking change
  - if you don't specify the number of digits to round to, the local format will be used (and it usually rounds numbers to 0 digits, instead of not rounding previously), e.g. `{{ 3.141592 | percent }}` will output `314%` for the locale `en-US` instead of `314.1592%` previously.

Fixes #10809, #9524, #7008, #9324, #7590, #6724, #3429, #17576, #17478, #17319, #17200, #16838, #16624, #16625, #16591, #14131, #12632, #11376, #11187

PR Close #18284
2017-08-22 15:43:58 -05:00
a73389bc71 build(common): add generated i18n locale data files (#18284)
PR Close #18284
2017-08-22 15:43:04 -05:00
33d250ffaa build(common): extract i18n locale data from cldr (#18284)
PR Close #18284
2017-08-22 15:43:04 -05:00
409688fe17 feat(animations): report errors when invalid CSS properties are detected (#18718)
Closes #18701

PR Close #18718
2017-08-21 20:38:22 -05:00
ec56760c9b refactor(common): remove deprecated NgFor (#18758)
BREAKING CHANGE: `NgFor` has been removed as it was deprecated since v4. Use `NgForOf` instead. This does not impact the use of`*ngFor` in your templates.

PR Close #18758
2017-08-21 18:11:01 -05:00
7ce9e06dab fix(aio): do not redirect API pages on archive and next deployments (#18791)
PR Close #18791
2017-08-21 17:32:10 -05:00
8ea6c56fe1 fix(compiler-cli): propagate preserveWhitespaces option to codegen (#18773)
PR Close #18773
2017-08-21 17:32:10 -05:00
c0ba2b9ca7 docs(aio): add ngAtlanta to the events page (#18649)
PR Close #18649
2017-08-21 17:13:09 -05:00
fc7c858e62 docs(aio): update resources to include NinjaCodeGen Angular CRUD generator (#18518)
PR Close #18518
2017-08-21 17:13:01 -05:00
55d151a82d refactor(common): remove usage of deprecated Renderer (#17528)
PR Close #17528
2017-08-21 13:24:40 -05:00
5a1b9a34df style(animations): format integration spec (#18805) 2017-08-21 11:07:28 -07:00
70628112e8 fix(animations): restore auto-style support for removed DOM nodes (#18787)
PR Close #18787
2017-08-18 23:31:10 -05:00
29aa8b33df fix(animations): make sure animation cancellations respect AUTO style values (#18787)
Closes #17450

PR Close #18787
2017-08-18 23:31:10 -05:00
e25f05ae7c fix(animations): make sure @.disabled respects disabled parent/sub animation sequences (#18715)
Prior to this fix if @parent and @child animations ran at the same
time within a disabled region then there was a chance that a @child
sub animation would never complete. This would cause *directives to
never close a removal when a @child trigger was placed on them. This
patch fixes this issue.

PR Close #18715
2017-08-18 23:30:28 -05:00
791c7efe29 fix(animations): ensure animations are disabled on the element containing the @.disabled flag (#18714)
Prior to fix this fix, @.disabled would only work to disable child
animations. Now it will also disable animations for the element that has
the @.disabled flag (which makes more sense).

PR Close #18714
2017-08-18 23:28:07 -05:00
2159342038 feat(animations): allow @.disabled property to work without an expression (#18713)
PR Close #18713
2017-08-18 23:28:04 -05:00
e228f2caa6 fix(compiler-cli): use forward slashes for ts.resolveModuleName (#18784)
Windows paths have back slashes, but TypeScript expects to always have forward slashes.

In other places where this call happens (like `src/compiler_host.ts`) the same fix is present.

PR Close #18784
2017-08-18 22:28:08 -05:00
7522987a51 refactor(common): remove deprecated NgTemplateOutlet#ngOutletContext (#18780)
BREAKING CHANGE: `NgTemplateOutlet#ngOutletContext` has been removed as it was deprecated since v4. Use `NgTemplateOutlet#ngTemplateOutletContext` instead.

PR Close #18780
2017-08-18 22:28:01 -05:00
Joe
ff6a20d138 docs(aio): fix card inconsistency (#18726)
PR Close #18726
2017-08-18 22:27:48 -05:00
4eb1f91bee ci(aio): Refactored payload size script, add script to track payload (#18517)
PR Close #18517
2017-08-18 22:27:38 -05:00
f53f7241a0 fix(core): correct order in ContentChildren query result (#18326)
Fixes #16568

PR Close #18326
2017-08-18 22:27:30 -05:00
f2a2a6b478 refactor(core): remove deprecated Testability#findBindings (#18782)
BREAKING CHANGE: `Testability#findBindings` has been removed as it was deprecated since v4. Use `Testability#findProviders` instead.

PR Close #18782
2017-08-18 17:13:16 -05:00
d61b9021e0 refactor(core): remove deprecated DebugNode#source (#18779)
BREAKING CHANGE: `DebugNode#source` has been removed as it was deprecated since v4.

PR Close #18779
2017-08-18 17:13:16 -05:00
499d05ddee refactor(compiler): remove option useDebug (#18778)
BREAKING CHANGE: the option `useDebug` for the compiler has been removed as it had no effect and was deprecated since v4.

PR Close #18778
2017-08-18 17:13:16 -05:00
b8a3736275 build(aio): do not auto-link code elements already inside a link (#18776)
Closes #18769

PR Close #18776
2017-08-18 17:13:16 -05:00
7d72d0eb9b refactor(compiler): align &ngsp; handling with Angular Dart implementation (#18774)
PR Close #18774
2017-08-18 17:13:15 -05:00
Tea
7f4c964eef docs(aio): typo in template-syntax guide (#18765)
PR Close #18765
2017-08-18 17:13:15 -05:00
be9713c6e2 refactor(core): remove deprecated ChangeDetectionRef argument in DifferFactory#create (#18757)
BREAKING CHANGE: `DifferFactory.create` no longer takes ChangeDetectionRef as a first argument as it was not used and deprecated since v4.

PR Close #18757
2017-08-18 13:23:47 -05:00
596e9f4e04 refactor(core): remove deprecated TrackByFn (#18757)
BREAKING CHANGE: `TrackByFn` has been removed because it was deprecated since v4. Use `TrackByFunction` instead.

PR Close #18757
2017-08-18 13:23:46 -05:00
da14391cff docs(aio): update resource for codelyzer (#18742)
PR Close #18742
2017-08-18 13:23:26 -05:00
60c803649b test(aio): fix error logged during tests (#18659)
The fixed test expected there to be a doc version without a URL. This used to be
the case but not any more. As a result, an error was logged in the test output
(but no failure).

This commit fixes it by ensuring that a version without a URL exists.

PR Close #18659
2017-08-18 13:23:16 -05:00
17b71ae382 docs(aio): move code snippet to appropriate location (#18650)
PR Close #18650
2017-08-18 13:23:09 -05:00
a56468cf2f refactor(platform-webworker): remove deprecated PRIMITIVE (#18761)
BREAKING CHANGE: `PRIMITIVE` has been removed as it was deprecated since v4. Use `SerializerTypes.PRIMITIVE` instead.

PR Close #18761
2017-08-17 18:02:00 -05:00
d7f42bfbe6 refactor(platform-browser): remove deprecated NgProbeToken (#18760)
BREAKING CHANGE: `NgProbeToken` has been removed from `@angular/platform-browser` as it was deprecated since v4. Import it from `@angular/core` instead.

PR Close #18760
2017-08-17 18:01:52 -05:00
8f413268cf refactor(core): remove deprecated parameter for ErrorHandler (#18759)
BREAKING CHANGE: `ErrorHandler` no longer takes a parameter as it was not used and deprecated since v4.

PR Close #18759
2017-08-17 18:01:41 -05:00
2a62d9f056 build(packaging): increase node memory for tests (#18755)
PR Close #18755
2017-08-17 18:01:32 -05:00
5f5a8e1da6 docs(aio): typo in metadata guide (#18730)
PR Close #18730
2017-08-17 18:01:20 -05:00
6e3498ca8e fix(tsc-wrapped): add metadata for type declarations (#18704)
Closes #18675

test(tsc-wrapped): fix collector tests

refactor(tsc-wrapped): change `__symbolic` to `interface` for `TypeAliasDeclaration`

tsc-wrapped: reword test

PR Close #18704
2017-08-17 18:01:10 -05:00
7bfd850493 refactor(compiler): add missing test to compare core and compiler metadata (#18739)
PR Close #18739
2017-08-17 18:00:55 -05:00
ffb1553282 refactor(compiler): make the new ngc API independent of tsickle (#18739)
This changes `performCompile` / `program.emit` to not tsickle automatically,
but allows to pass in an `emitCallback` in which tsickle can be executed.
2017-08-17 18:00:52 -05:00
56a5b02d04 test: add cli integration test (#18738)
This adds cli integration test which creates a hello-world and tests it.

PR Close #18738
2017-08-16 22:00:36 -05:00
0cc77b4a69 refactor(compiler): split compiler and core (#18683)
After this, neither @angular/compiler nor @angular/comnpiler-cli depend
on @angular/core.

This add a duplication of some interfaces and enums which is stored
in @angular/compiler/src/core.ts

BREAKING CHANGE:
- `@angular/platform-server` now additionally depends on
  `@angular/platform-browser-dynamic` as a peer dependency.


PR Close #18683
2017-08-16 17:58:53 -05:00
a0ca01d580 refactor(compiler): drop typings tests for TypeScript 2.1 (#18683) 2017-08-16 17:58:48 -05:00
2da45e629d fix(tsc-wrapped): make test.sh tools run the tsc-wrapped tests again (#18683) 2017-08-16 17:58:44 -05:00
845c68fdb3 fix(animations): resolve error when using AnimationBuilder with platform-server (#18642)
Use an injected DOCUMENT instead of assuming the global 'document'
exists.

Fixes #18635.

PR Close #18642
2017-08-16 17:47:42 -05:00
21c44672c4 build(packaging): increase node memory for tests (#18731)
PR Close #18731
2017-08-16 17:47:34 -05:00
83713ddea4 feat(common): add an empty DeprecatedI18NPipesModule module (#18737)
Adding an empty module to ease the migration to the i18n pipes.

PR Close #18737
2017-08-16 17:47:24 -05:00
3a500981ef feat(compiler): allow multiple exportAs names
This change allows users to specify multiple exportAs names for a
directive by giving a comma-delimited list inside the string.

The primary motivation for this change is to allow these names to be
changed in a backwards compatible way.
2017-08-16 15:31:48 -07:00
0d45828460 feat(forms): add updateOn and ngFormOptions to NgForm
This commit introduces a new Input property called
`ngFormOptions` to the `NgForm` directive. You can use it
to set default `updateOn` values for all the form's child
controls. This default will be used unless the child has
already explicitly set its own `updateOn` value in
`ngModelOptions`.

Potential values: `change` | `blur` | `submit`

```html
<form [ngFormOptions]="{updateOn: blur}">
  <input name="one" ngModel>  <!-- will update on blur-->
</form>
```

For more context, see [#18577](https://github.com/angular/angular/pull/18577).
2017-08-16 15:25:34 -07:00
43226cb93d feat(compiler): use typescript for resolving resource paths
This can also be customized via the new method `resourceNameToFileName` in the
`CompilerHost`.
2017-08-16 15:24:48 -07:00
2572bf508f feat(compiler): make .ngsummary.json files portable
This also allows to customize the filePaths in `.ngsummary.json` file
via the new methods `toSummaryFileName` and `fromSummaryFileName`
on the `CompilerHost`.
2017-08-16 15:24:48 -07:00
6a1ab61cce refactor(compiler): simplify the CompilerHost used for transformers
- remove unneeded methods (`getNgCanonicalFileName`, `assumeFileExists`)
- simplify moduleName <-> fileName conversion logic as we don’t need to
  account for `genDir` anymore.
- rename `createNgCompilerHost` -> `createCompilerHost`
2017-08-16 15:24:48 -07:00
27d5058e01 refactor(compiler): extract a BaseAotCompilerHost that is shared between the old and new logic 2017-08-16 15:24:48 -07:00
1329 changed files with 47905 additions and 3839 deletions

View File

@ -41,7 +41,7 @@ jobs:
- restore_cache:
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}
- run: bazel run @build_bazel_rules_typescript_node//:bin/npm install
- run: bazel run @nodejs//:npm install
- run: bazel build packages/...
- save_cache:
key: angular-{{ .Branch }}-{{ checksum "npm-shrinkwrap.json" }}

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ bazel-*
e2e_test.*
node_modules
bower_components
tools/gulp-tasks/cldr/cldr-data/
# Include when developing application packages.
pubspec.lock

View File

@ -70,7 +70,6 @@ groups:
- "tools/*"
exclude:
- "tools/public_api_guard/*"
- "tools/ngc-wrapped/*"
- "aio/*"
users:
- IgorMinar #primary
@ -138,7 +137,7 @@ groups:
files:
- "packages/tsc-wrapped/*"
- "packages/compiler-cli/*"
- "tools/ngc-wrapped/*"
- "packages/bazel/*"
users:
- alexeagle
- chuckjaz

View File

@ -1,17 +1,21 @@
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "build_bazel_rules_typescript",
remote = "https://github.com/bazelbuild/rules_typescript.git",
tag = "0.0.5",
name = "build_bazel_rules_nodejs",
remote = "https://github.com/bazelbuild/rules_nodejs.git",
tag = "0.0.2",
)
load("@build_bazel_rules_typescript//:defs.bzl", "node_repositories")
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")
node_repositories(package_json = "//:package.json")
node_repositories(package_json = ["//:package.json"])
git_repository(
name = "build_bazel_rules_angular",
remote = "https://github.com/bazelbuild/rules_angular.git",
tag = "0.0.1",
local_repository(
name = "build_bazel_rules_typescript",
path = "node_modules/@bazel/typescript",
)
local_repository(
name = "angular",
path = "packages/bazel",
)

View File

@ -26,7 +26,7 @@ Here are the most important tasks you might need to use:
* `yarn docs-lint` - check that the doc gen code follows our style rules.
* `yarn docs-test` - run the unit tests for the doc generation code.
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally.
* `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally. Add the option `-- --local` to use your local version of Angular contained in the "dist" folder.
* `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`.
* `yarn generate-plunkers` - generate the plunker files that are used by the `live-example` tags in the docs.
* `yarn generate-zips` - generate the zip files from the examples. Zip available via the `live-example` tags in the docs.
@ -34,6 +34,7 @@ Here are the most important tasks you might need to use:
* `yarn example-e2e` - run all e2e tests for examples
- `yarn example-e2e -- --setup` - force webdriver update & other setup, then run tests
- `yarn example-e2e -- --filter=foo` - limit e2e tests to those containing the word "foo"
- `yarn example-e2e -- --setup --local` - run e2e tests with the local version of Angular contained in the "dist" folder
* `yarn build-ie-polyfills` - generates a js file of polyfills that can be loaded in Internet Explorer.

View File

@ -0,0 +1,6 @@
// #docregion import-locale
import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/i18n_data/locale_fr';
registerLocaleData(localeFr);
// #enddocregion import-locale

View File

@ -0,0 +1,7 @@
// #docregion import-locale-extra
import { registerLocaleData } from '@angular/common';
import localeEnGB from '@angular/common/i18n_data/locale_en-GB';
import localeEnGBExtra from '@angular/common/i18n_data/extra/locale_en-GB';
registerLocaleData(localeEnGB, localeEnGBExtra);
// #enddocregion import-locale-extra

View File

@ -28,7 +28,7 @@ describe('Pipes', function () {
it('should be able to toggle birthday formats', function () {
let birthDayEle = element(by.css('hero-birthday2 > p'));
expect(birthDayEle.getText()).toEqual(`The hero's birthday is 4/15/1988`);
expect(birthDayEle.getText()).toEqual(`The hero's birthday is 4/15/88`);
let buttonEle = element(by.cssContainingText('hero-birthday2 > button', 'Toggle Format'));
expect(buttonEle.isDisplayed()).toBe(true);
buttonEle.click().then(function() {

View File

@ -363,6 +363,10 @@ Those _npm_ commands are long and difficult to remember.
Add the following _npm_ convenience script to the `package.json` so you can compile and rollup in one command.
<code-example language="json">
"build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup-config.js",
</code-example>
Open a terminal window and try it.
<code-example language="none" class="code-shell">
@ -526,10 +530,10 @@ Compiling with AOT presupposes certain supporting files, most of them discussed
</code-pane>
</code-tabs>
Extend the `scripts` section of the `package.json` with these npm scripts:
With the following npm script in the `scripts` section of the `package.json`, you can easily serve
the AOT-compiled application:
<code-example language="json">
"build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup-config.js",
"serve:aot": "lite-server -c bs-config.aot.json",
</code-example>
@ -545,7 +549,7 @@ Copy the AOT distribution files into the `/aot` folder with the node script:
</div>
Now AOT-compile the app and launch it with the `lite-server`:
Now AOT-compile the app and launch:
<code-example language="none" class="code-shell">
npm run build:aot && npm run serve:aot

View File

@ -347,7 +347,7 @@ Here are the features which may require additional polyfills:
<td>
[Date](api/common/DatePipe), [currency](api/common/CurrencyPipe), [decimal](api/common/DecimalPipe) and [percent](api/common/PercentPipe) pipes
If you use the following deprecated i18n pipes: [date](api/common/DeprecatedDatePipe), [currency](api/common/DeprecatedCurrencyPipe), [decimal](api/common/DeprecatedDecimalPipe) and [percent](api/common/DeprecatedPercentPipe)
</td>
<td>

View File

@ -126,7 +126,7 @@ http
err => {
console.log('Something went wrong!');
}
});
);
```
#### Getting error details
@ -141,7 +141,7 @@ In both cases, you can look at the `HttpErrorResponse` to figure out what happen
http
.get<ItemsResponse>('/api/items')
.subscribe(
data => {...},
data => {...},
(err: HttpErrorResponse) => {
if (err.error instanceof Error) {
// A client-side or network error occurred. Handle it accordingly.
@ -152,7 +152,7 @@ http
console.log(`Backend returned code ${err.status}, body was: ${err.error}`);
}
}
});
);
```
#### `.retry()`

View File

@ -40,6 +40,28 @@ You need to build and deploy a separate version of the application for each supp
{@a i18n-attribute}
## i18n pipes
Angular pipes can help you with internationalization: the `DatePipe`, `CurrencyPipe`, `DecimalPipe`
and `PercentPipe` use locale data to format your data based on your `LOCALE_ID`.
By default Angular only contains locale data for the language `en-US`, if you set the value of
`LOCALE_ID` to another locale, you will have to import new locale data for this language:
<code-example path="i18n/src/app/app.locale_data.ts" region="import-locale" title="src/app/app.locale_data.ts" linenums="false">
</code-example>
<div class="l-sub-section">
Note that the files in `@angular/common/i18n_data` contain most of the locale data that you will
need, but some advanced formatting options might only be available in the extra dataset that you can
import from `@angular/common/i18n_data/extra`:
<code-example path="i18n/src/app/app.locale_data_extra.ts" region="import-locale-extra" title="src/app/app.locale_data_extra.ts" linenums="false">
</code-example>
</div>
## Mark text with the _i18n_ attribute
The Angular `i18n` attribute is a marker for translatable content.

View File

@ -16,7 +16,7 @@ In the following example, the `@Component()` metadata object and the class const
```typescript
@Component({
selector: 'app-typical',
template: 'div>A typical component for {{data.name}}</div>
template: '<div>A typical component for {{data.name}}</div>'
)}
export class TypicalComponent {
@Input() data: TypicalData;

View File

@ -46,24 +46,6 @@ Inside the interpolation expression, you flow the component's `birthday` value t
function on the right. All pipes work this way.
<div class="l-sub-section">
The `Date` and `Currency` pipes need the *ECMAScript Internationalization API*.
Safari and other older browsers don't support it. You can add support with a polyfill.
<code-example language="html">
&lt;script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en"&gt;&lt;/script&gt;
</code-example>
</div>
## Built-in pipes

View File

@ -313,7 +313,7 @@ It's intended source is implicit.
Angular sets `let-hero` to the value of the context's `$implicit` property
which `NgFor` has initialized with the hero for the current iteration.
* The [API guide](api/common/NgFor "API: NgFor")
* The [API guide](api/common/NgForOf "API: NgFor")
describes additional `NgFor` directive properties and context properties.
These microsyntax mechanisms are available to you when you write your own structural directives.

View File

@ -1155,7 +1155,7 @@ other HTML elements, attributes, properties, and components.
They are usually applied to elements as if they were HTML attributes, hence the name.
Many details are covered in the [_Attribute Directives_](guide/attribute-directives) guide.
Many NgMdules such as the [`RouterModule`](guide/router "Routing and Navigation")
Many NgModules such as the [`RouterModule`](guide/router "Routing and Navigation")
and the [`FormsModule`](guide/forms "Forms") define their own attribute directives.
This section is an introduction to the most commonly used attribute directives:
@ -1361,8 +1361,8 @@ to group elements when there is no suitable host element for the directive.
_This_ section is an introduction to the common structural directives:
* [`NgIf`](guide/template-syntax#ngIf) - conditionally add or remove an element from the DOM
* [`NgFor`](guide/template-syntax#ngFor) - repeat a template for each item in a list
* [`NgSwitch`](guide/template-syntax#ngSwitch) - a set of directives that switch among alternative views
* [NgForOf](guide/template-syntax#ngFor) - repeat a template for each item in a list
<hr/>
@ -1437,18 +1437,18 @@ described below.
{@a ngFor}
### NgFor
### NgForOf
`NgFor` is a _repeater_ directive &mdash; a way to present a list of items.
`NgForOf` is a _repeater_ directive &mdash; a way to present a list of items.
You define a block of HTML that defines how a single item should be displayed.
You tell Angular to use that block as a template for rendering each item in the list.
Here is an example of `NgFor` applied to a simple `<div>`:
Here is an example of `NgForOf` applied to a simple `<div>`:
<code-example path="template-syntax/src/app/app.component.html" region="NgFor-1" title="src/app/app.component.html" linenums="false">
</code-example>
You can also apply an `NgFor` to a component element, as in this example:
You can also apply an `NgForOf` to a component element, as in this example:
<code-example path="template-syntax/src/app/app.component.html" region="NgFor-2" title="src/app/app.component.html" linenums="false">
</code-example>
@ -1485,10 +1485,10 @@ Learn about the _microsyntax_ in the [_Structural Directives_](guide/structural-
### Template input variables
The `let` keyword before `hero` creates a _template input variable_ called `hero`.
The `ngFor` directive iterates over the `heroes` array returned by the parent component's `heroes` property
The `NgForOf` directive iterates over the `heroes` array returned by the parent component's `heroes` property
and sets `hero` to the current item from the array during each iteration.
You reference the `hero` input variable within the `ngFor` host element
You reference the `hero` input variable within the `NgForOf` host element
(and within its descendents) to access the hero's properties.
Here it is referenced first in an interpolation
and then passed in a binding to the `hero` property of the `<hero-detail>` component.
@ -1501,7 +1501,7 @@ Learn more about _template input variables_ in the
#### *ngFor with _index_
The `index` property of the `NgFor` directive context returns the zero-based index of the item in each iteration.
The `index` property of the `NgForOf` directive context returns the zero-based index of the item in each iteration.
You can capture the `index` in a template input variable and use it in the template.
The next example captures the `index` in a variable named `i` and displays it with the hero name like this.
@ -1511,8 +1511,8 @@ The next example captures the `index` in a variable named `i` and displays it wi
<div class="l-sub-section">
Learn about the other `NgFor` context values such as `last`, `even`,
and `odd` in the [NgFor API reference](api/common/NgFor).
Learn about the other `NgForOf` context values such as `last`, `even`,
and `odd` in the [NgForOf API reference](api/common/NgForOf).
</div>
@ -1520,7 +1520,7 @@ and `odd` in the [NgFor API reference](api/common/NgFor).
#### *ngFor with _trackBy_
The `NgFor` directive may perform poorly, especially with large lists.
The `NgForOf` directive may perform poorly, especially with large lists.
A small change to one item, an item removed, or an item added can trigger a cascade of DOM manipulations.
For example, re-querying the server could reset the list with all new hero objects.
@ -1531,7 +1531,7 @@ But Angular sees only a fresh list of new object references.
It has no choice but to tear down the old DOM elements and insert all new DOM elements.
Angular can avoid this churn with `trackBy`.
Add a method to the component that returns the value `NgFor` _should_ track.
Add a method to the component that returns the value `NgForOf` _should_ track.
In this case, that value is the hero's `id`.
<code-example path="template-syntax/src/app/app.component.ts" region="trackByHeroes" title="src/app/app.component.ts" linenums="false">

View File

@ -10,13 +10,11 @@ Angular is a platform that makes it easy to build applications with the web. Ang
<p class="card-footer">Angular in Action</p>
</a>
<div class="docs-card">
<a href="guide/quickstart" class="docs-card" title="Angular Quickstart">
<section>Get Going with Angular</section>
<p>Get going on your own environment with the Quickstart.</p>
<p class="card-footer" >
<a href="guide/quickstart" title="Angular Quickstart">Quickstart</a>
</p>
</div>
<p class="card-footer">Quickstart</p>
</a>
<a href="guide/architecture" class="docs-card" title="Angular Architecture">
<section>Fundamentals</section>

View File

@ -37,6 +37,12 @@
<td>London, United Kingdom</td>
<td>November 07, 2017</td>
</tr>
<!-- ngAtlanta-->
<tr>
<th><a href="http://ng-atl.org/" title="ngAtlanta">ngAtlanta</a></th>
<td>Atlanta, Georgia</td>
<td>January 30, 2018</td>
</tr>
</tbody>
</table>
</article>

View File

@ -202,7 +202,7 @@
"url": "https://cli.angular.io"
},
"d1": {
"desc": "A set of tslint rules for static code analysis of Angular TypeScript projects.",
"desc": "Static analysis for Angular projects.",
"logo": "",
"rev": true,
"title": "Codelyzer",
@ -221,6 +221,13 @@
"rev": true,
"title": "Compodoc",
"url": "https://github.com/compodoc/compodoc"
},
"ncg": {
"desc": "Generate several types of CRUD apps complete with e2e testing using template-sets for Angular, Material Design, Bootstrap, Kendo UI, Ionic, ...",
"logo": "https://avatars3.githubusercontent.com/u/27976684",
"rev": true,
"title": "NinjaCodeGen - Angular CRUD Generator",
"url": "https://ninjaCodeGen.com"
}
}
},
@ -324,7 +331,7 @@
"title": "Amexio - Angular Extensions",
"url": "http://www.amexio.tech/",
"logo": "http://www.amexio.org/amexio-logo.png"
}
}
}
}
}

View File

@ -124,6 +124,7 @@
"unist-util-filter": "^0.2.1",
"unist-util-source": "^1.0.1",
"unist-util-visit": "^1.1.1",
"unist-util-visit-parents": "^1.1.1",
"vrsource-tslint-rules": "^4.0.1",
"watchr": "^3.0.1",
"yargs": "^7.0.2"

View File

@ -2,9 +2,13 @@
set -u -e -o pipefail
declare -A limitUncompressed
limitUncompressed=(["inline"]=1600 ["main"]=525000 ["polyfills"]=38000)
declare -A limitGzip7
limitGzip7=(["inline"]=1000 ["main"]=127000 ["polyfills"]=12500)
declare -A limitGzip9
limitGzip9=(["inline"]=1000 ["main"]=127000 ["polyfills"]=12500)
declare -A payloadLimits
payloadLimits["aio", "uncompressed", "inline"]=1600
payloadLimits["aio", "uncompressed", "main"]=525000
payloadLimits["aio", "uncompressed", "polyfills"]=38000
payloadLimits["aio", "gzip7", "inline"]=1000
payloadLimits["aio", "gzip7", "main"]=127000
payloadLimits["aio", "gzip7", "polyfills"]=12500
payloadLimits["aio", "gzip9", "inline"]=1000
payloadLimits["aio", "gzip9", "main"]=127000
payloadLimits["aio", "gzip9", "polyfills"]=12500

View File

@ -4,79 +4,10 @@ set -eu -o pipefail
readonly thisDir=$(cd $(dirname $0); pwd)
readonly parentDir=$(dirname $thisDir)
readonly PROJECT_NAME="angular-payload-size"
# Track payload size functions
source ../scripts/ci/payload-size.sh
source ${thisDir}/_payload-limits.sh
failed=false
payloadData=""
for filename in dist/*.bundle.js; do
size=$(stat -c%s "$filename")
label=$(echo "$filename" | sed "s/.*\///" | sed "s/\..*//")
payloadData="$payloadData\"uncompressed/$label\": $size, "
trackPayloadSize "aio" "dist/*.bundle.js" true true
gzip -7 $filename -c >> "${filename}7.gz"
size7=$(stat -c%s "${filename}7.gz")
payloadData="$payloadData\"gzip7/$label\": $size7, "
gzip -9 $filename -c >> "${filename}9.gz"
size9=$(stat -c%s "${filename}9.gz")
payloadData="$payloadData\"gzip9/$label\": $size9, "
if [[ $size -gt ${limitUncompressed[$label]} ]]; then
failed=true
echo "Uncompressed $label size is $size which is greater than ${limitUncompressed[$label]}"
elif [[ $size7 -gt ${limitGzip7[$label]} ]]; then
failed=true
echo "Gzip7 $label size is $size7 which is greater than ${limitGzip7[$label]}"
elif [[ $size9 -gt ${limitGzip9[$label]} ]]; then
failed=true
echo "Gzip9 $label size is $size9 which is greater than ${limitGzip9[$label]}"
fi
done
# Add Timestamp
timestamp=$(date +%s)
payloadData="$payloadData\"timestamp\": $timestamp, "
# Add change source: application, dependencies, or 'application+dependencies'
applicationChanged=false
dependenciesChanged=false
if [[ $(git diff --name-only $TRAVIS_COMMIT_RANGE $parentDir | grep -v aio/yarn.lock | grep -v content) ]]; then
applicationChanged=true
fi
if [[ $(git diff --name-only $TRAVIS_COMMIT_RANGE $parentDir/yarn.lock) ]]; then
dependenciesChanged=true
fi
if $dependenciesChanged && $applicationChanged; then
change='application+dependencies'
elif $dependenciesChanged; then
# only yarn.lock changed
change='dependencies'
elif $applicationChanged; then
change='application'
else
# Nothing changed in aio/
exit 0
fi
message=$(echo $TRAVIS_COMMIT_MESSAGE | sed 's/"/\\"/g' | sed 's/\\/\\\\/g')
payloadData="$payloadData\"change\": \"$change\", \"message\": \"$message\""
payloadData="{${payloadData}}"
echo $payloadData
if [[ "$TRAVIS_PULL_REQUEST" == "false" ]]; then
readonly safeBranchName=$(echo $TRAVIS_BRANCH | sed -e 's/\./_/g')
readonly dbPath=/payload/aio/$safeBranchName/$TRAVIS_COMMIT
# WARNING: FIREBASE_TOKEN should NOT be printed.
set +x
firebase database:update --data "$payloadData" --project $PROJECT_NAME --confirm --token "$ANGULAR_PAYLOAD_FIREBASE_TOKEN" $dbPath
fi
if [[ $failed = true ]]; then
exit 1
fi

View File

@ -310,13 +310,11 @@ describe('AppComponent', () => {
expect(locationService.go).toHaveBeenCalledWith(versionWithUrl.url);
});
// The current docs version should not have an href
// This may change when we perfect our docs versioning approach
it('should not navigate when change to a version without a url', () => {
setupSelectorForTesting();
const versionWithoutUrlIndex = component.docVersions.findIndex(v => !v.url);
const versionWithoutUrl = component.docVersions[versionWithoutUrlIndex];
selectElement.triggerEventHandler('change', { option: versionWithoutUrl, index: versionWithoutUrlIndex});
const versionWithoutUrlIndex = component.docVersions.length;
const versionWithoutUrl = component.docVersions[versionWithoutUrlIndex] = { title: 'foo', url: null };
selectElement.triggerEventHandler('change', { option: versionWithoutUrl, index: versionWithoutUrlIndex });
expect(locationService.go).not.toHaveBeenCalled();
});
});
@ -794,6 +792,10 @@ describe('AppComponent', () => {
createTestingModule('api', 'archive');
initializeTest();
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
createTestingModule('api/core/getPlatform', 'archive');
initializeTest();
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
});
it('should redirect to `docs` if deployment mode is `next` and not at a docs page', () => {
@ -824,6 +826,10 @@ describe('AppComponent', () => {
createTestingModule('api', 'next');
initializeTest();
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
createTestingModule('api/core/getPlatform', 'next');
initializeTest();
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
});
it('should not redirect to `docs` if deployment mode is `stable` and not at a docs page', () => {
@ -854,6 +860,10 @@ describe('AppComponent', () => {
createTestingModule('api', 'stable');
initializeTest();
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
createTestingModule('api/core/getPlatform', 'stable');
initializeTest();
expect(TestBed.get(LocationService).replace).not.toHaveBeenCalled();
});
});
});

View File

@ -131,7 +131,7 @@ export class AppComponent implements OnInit {
this.locationService.currentPath.subscribe(path => {
// Redirect to docs if we are in not in stable mode and are not hitting a docs page
// (i.e. we have arrived at a marketing page)
if (this.deployment.mode !== 'stable' && !/^(docs$|api$|guide|tutorial)/.test(path)) {
if (this.deployment.mode !== 'stable' && !/^(docs$|api|guide|tutorial)/.test(path)) {
this.locationService.replace('docs');
}
if (path === this.currentPath) {

View File

@ -1,4 +1,4 @@
const visit = require('unist-util-visit');
const visit = require('unist-util-visit-parents');
const is = require('hast-util-is-element');
const textContent = require('hast-util-to-string');
@ -17,8 +17,8 @@ module.exports = function autoLinkCode(getDocFromAlias) {
function autoLinkCodeImpl() {
return (ast) => {
visit(ast, node => {
if (is(node, 'code')) {
visit(ast, (node, ancestors) => {
if (is(node, 'code') && ancestors.every(ancestor => !is(ancestor, 'a'))) {
const docs = getDocFromAlias(textContent(node));
if (docs.length === 1 && autoLinkCodeImpl.docTypes.indexOf(docs[0].docType) !== -1) {
const link = {

View File

@ -36,4 +36,11 @@ describe('autoLinkCode post-processor', () => {
processor.$process([doc]);
expect(doc.renderedContent).toEqual('<code>MyClass</code>');
});
it('should ignore code items that are already inside a link', () => {
aliasMap.addDoc({ docType: 'class', id: 'MyClass', aliases: ['MyClass'], path: 'a/b/myclass' });
const doc = { docType: 'test-doc', renderedContent: '<a href="..."><div><code>MyClass</code></div></a>' };
processor.$process([doc]);
expect(doc.renderedContent).toEqual('<a href="..."><div><code>MyClass</code></div></a>');
});
});

View File

@ -7789,6 +7789,10 @@ unist-util-stringify-position@^1.0.0:
dependencies:
has "^1.0.1"
unist-util-visit-parents@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-1.1.1.tgz#7d3f56b5b039a3c6e2d16e51cc093f10e4755342"
unist-util-visit@^1.0.0, unist-util-visit@^1.1.0, unist-util-visit@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.1.1.tgz#e917a3b137658b335cb4420c7da2e74d928e4e94"

View File

@ -86,7 +86,7 @@ done
#######################################
isIgnoredDirectory() {
name=$(basename ${1})
if [[ -f "${1}" || "${name}" == "src" || "${name}" == "test" || "${name}" == "integrationtest" ]]; then
if [[ -f "${1}" || "${name}" == "src" || "${name}" == "test" || "${name}" == "integrationtest" || "${name}" == "i18n_data" ]]; then
return 0
else
return 1
@ -327,6 +327,16 @@ mapSources() {
fi
}
updateVersionReferences() {
NPM_DIR="$1"
(
echo "====== VERSION: Updating version references in ${NPM_DIR}"
cd ${NPM_DIR}
echo "====== EXECUTE: perl -p -i -e \"s/0\.0\.0\-PLACEHOLDER/${VERSION}/g\" $""(grep -ril 0\.0\.0\-PLACEHOLDER .)"
perl -p -i -e "s/0\.0\.0\-PLACEHOLDER/${VERSION}/g" $(grep -ril 0\.0\.0\-PLACEHOLDER .) < /dev/null 2> /dev/null
)
}
VERSION="${VERSION_PREFIX}${VERSION_SUFFIX}"
echo "====== BUILDING: Version ${VERSION}"
@ -419,11 +429,13 @@ if [[ ${BUILD_TOOLS} == true || ${BUILD_ALL} == true ]]; then
$(npm bin)/tsc -p packages/tsc-wrapped/tsconfig-build.json
cp ./packages/tsc-wrapped/package.json ./dist/packages-dist/tsc-wrapped
cp ./packages/tsc-wrapped/README.md ./dist/packages-dist/tsc-wrapped
(
cd dist/packages-dist/tsc-wrapped
echo "====== EXECUTE: perl -p -i -e \"s/0\.0\.0\-PLACEHOLDER/${VERSION}/g\" $""(grep -ril 0\.0\.0\-PLACEHOLDER .)"
perl -p -i -e "s/0\.0\.0\-PLACEHOLDER/${VERSION}/g" $(grep -ril 0\.0\.0\-PLACEHOLDER .) < /dev/null 2> /dev/null
)
updateVersionReferences dist/packages-dist/tsc-wrapped
rsync -a packages/bazel/ ./dist/packages-dist/bazel
# Remove BEGIN-INTERNAL...END-INTERAL blocks
# https://stackoverflow.com/questions/24175271/how-can-i-match-multi-line-patterns-in-the-command-line-with-perl-style-regex
perl -0777 -n -i -e "s/(?m)^.*BEGIN-INTERNAL[\w\W]*END-INTERNAL.*\n//g; print" $(grep -ril BEGIN-INTERNAL dist/packages-dist/bazel) < /dev/null 2> /dev/null
updateVersionReferences dist/packages-dist/bazel
fi
for PACKAGE in ${PACKAGES[@]}
@ -470,6 +482,11 @@ do
minify ${BUNDLES_DIR}
) 2>&1 | grep -v "as external dependency"
if [[ ${PACKAGE} == "common" ]]; then
echo "====== Copy i18n locale data"
rsync -a --exclude=*.d.ts --exclude=*.metadata.json ${OUT_DIR}/i18n_data/ ${NPM_DIR}/i18n_data
fi
else
echo "====== Copy ${PACKAGE} node tool"
rsync -a ${OUT_DIR}/ ${NPM_DIR}
@ -484,12 +501,7 @@ do
if [[ -d ${NPM_DIR} ]]; then
(
echo "====== VERSION: Updating version references"
cd ${NPM_DIR}
echo "====== EXECUTE: perl -p -i -e \"s/0\.0\.0\-PLACEHOLDER/${VERSION}/g\" $""(grep -ril 0\.0\.0\-PLACEHOLDER .)"
perl -p -i -e "s/0\.0\.0\-PLACEHOLDER/${VERSION}/g" $(grep -ril 0\.0\.0\-PLACEHOLDER .) < /dev/null 2> /dev/null
)
updateVersionReferences ${NPM_DIR}
fi
travisFoldEnd "build package: ${PACKAGE}"

View File

@ -42,3 +42,5 @@ gulp.task('serve', loadTask('serve', 'default'));
gulp.task('serve-examples', loadTask('serve', 'examples'));
gulp.task('changelog', loadTask('changelog'));
gulp.task('check-env', () => {/* this is a noop because the env test ran already above */});
gulp.task('cldr:extract', loadTask('cldr', 'extract'));
gulp.task('cldr:download', loadTask('cldr', 'download'));

View File

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

View File

@ -0,0 +1,19 @@
#!/bin/bash
set -u -e -o pipefail
declare -A payloadLimits
payloadLimits["hello_world__closure", "uncompressed", "bundle"]=106000
payloadLimits["hello_world__closure", "gzip7", "bundle"]=35000
payloadLimits["hello_world__closure", "gzip9", "bundle"]=35000
payloadLimits["cli-hello-world", "uncompressed", "inline"]=1500
payloadLimits["cli-hello-world", "uncompressed", "main"]=183000
payloadLimits["cli-hello-world", "uncompressed", "polyfills"]=63000
payloadLimits["cli-hello-world", "gzip7", "inline"]=900
payloadLimits["cli-hello-world", "gzip7", "main"]=48000
payloadLimits["cli-hello-world", "gzip7", "polyfills"]=21000
payloadLimits["cli-hello-world", "gzip9", "inline"]=900
payloadLimits["cli-hello-world", "gzip9", "main"]=48000
payloadLimits["cli-hello-world", "gzip9", "polyfills"]=21000

View File

@ -0,0 +1,10 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "node_modules",
srcs = glob([
"node_modules/**/*.js",
"node_modules/**/*.d.ts",
"node_modules/**/*.json",
])
)

View File

@ -0,0 +1,30 @@
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "build_bazel_rules_nodejs",
remote = "https://github.com/bazelbuild/rules_nodejs.git",
tag = "0.0.2",
)
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories")
node_repositories(package_json = ["//:package.json"])
local_repository(
name = "build_bazel_rules_typescript",
path = "node_modules/@bazel/typescript",
)
local_repository(
name = "angular",
path = "node_modules/@angular/bazel",
)
git_repository(
name = "io_bazel_rules_sass",
remote = "https://github.com/bazelbuild/rules_sass.git",
tag = "0.0.2",
)
load("@io_bazel_rules_sass//sass:sass.bzl", "sass_repositories")
sass_repositories()

View File

@ -0,0 +1,23 @@
// WORKAROUND https://github.com/angular/angular/issues/18810
// This file is required to run ngc on angular libraries, to write files like
// node_modules/@angular/core/core.ngsummary.json
{
"compilerOptions": {
"lib": [
"dom",
"es2015"
],
"experimentalDecorators": true,
"types": []
},
"include": [
"node_modules/@angular/**/*"
],
"exclude": [
"node_modules/@angular/bazel/**",
"node_modules/@angular/compiler-cli/**",
// Workaround bug introduced by 079d884
"node_modules/@angular/common/i18n_data*",
"node_modules/@angular/tsc-wrapped/**"
]
}

View File

@ -0,0 +1,25 @@
{
"name": "angular-bazel",
"description": "example and integration test for building Angular apps with Bazel",
"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/core": "file:../../dist/packages-dist/core",
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
"rxjs": "5.3.1",
"zone.js": "0.8.6"
},
"devDependencies": {
"@angular/bazel": "file:../../dist/packages-dist/bazel",
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
"@bazel/typescript": "0.0.7",
"typescript": "~2.3.1"
},
"scripts": {
"postinstall": "ngc -p angular.tsconfig.json",
"test": "bazel build ..."
}
}

View File

@ -0,0 +1,11 @@
load("@angular//:index.bzl", "ng_module")
# Allow targets under sub-packages to reference the tsconfig.json file
exports_files(["tsconfig.json"])
ng_module(
name = "app",
srcs = ["app.module.ts"],
deps = ["//src/hello-world"],
tsconfig = ":tsconfig.json",
)

View File

@ -0,0 +1,9 @@
import {HelloWorldModule} from './hello-world/hello-world.module';
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
@NgModule({
imports: [BrowserModule, HelloWorldModule]
})
export class AppModule {}

View File

@ -0,0 +1,19 @@
package(default_visibility = ["//visibility:public"])
load("@angular//:index.bzl", "ng_module")
load("@io_bazel_rules_sass//sass:sass.bzl", "sass_binary")
sass_binary(
name = "styles",
src = "hello-world.component.scss",
deps = [
"//src/shared:colors",
"//src/shared:fonts",
],
)
ng_module(
name = "hello-world",
srcs = glob(["*.ts"]),
tsconfig = "//src:tsconfig.json",
assets = [":styles"],
)

View File

@ -0,0 +1,12 @@
@import "src/shared/fonts";
@import "src/shared/colors";
html {
body {
font-family: $default-font-stack;
h1 {
font-family: $modern-font-stack;
color: $example-red;
}
}
}

View File

@ -0,0 +1,15 @@
import {Component, NgModule} from '@angular/core';
@Component({
selector: 'hello-world-app',
template: `
<div>Hello {{ name }}!</div>
<input type="text" [value]="name" (input)="name = $event.target.value"/>
`,
// TODO: might be better to point to .scss so this looks valid at design-time
styleUrls: ['./styles.css']
})
export class HelloWorldComponent {
name: string = 'world';
}

View File

@ -0,0 +1,8 @@
import {HelloWorldComponent} from './hello-world.component';
import {NgModule} from '@angular/core';
@NgModule({
declarations: [HelloWorldComponent],
bootstrap: [HelloWorldComponent],
})
export class HelloWorldModule {}

View File

@ -0,0 +1,13 @@
package(default_visibility = ["//visibility:public"])
load("@io_bazel_rules_sass//sass:sass.bzl", "sass_library")
sass_library(
name = "colors",
srcs = ["_colors.scss"],
)
sass_library(
name = "fonts",
srcs = ["_fonts.scss"],
)

View File

@ -0,0 +1,2 @@
$example-blue: #0000ff;
$example-red: #ff0000;

View File

@ -0,0 +1,2 @@
$default-font-stack: Cambria, "Hoefler Text", Utopia, "Liberation Serif", "Nimbus Roman No9 L Regular", Times, "Times New Roman", serif;
$modern-font-stack: Constantia, "Lucida Bright", Lucidabright, "Lucida Serif", Lucida, "DejaVu Serif", "Bitstream Vera Serif", "Liberation Serif", Georgia, serif;

View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"lib": [
"dom",
"es5",
"es2015.collection",
"es2015.iterable",
"es2015.promise"
]
}
}

70
integration/ng-cli-create.sh Executable file
View File

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

View File

@ -4,6 +4,10 @@ set -e -o pipefail
cd `dirname $0`
# Track payload size functions
source ../scripts/ci/payload-size.sh
source ./_payload-limits.sh
# Workaround https://github.com/yarnpkg/yarn/issues/2165
# Yarn will cache file://dist URIs and not update Angular code
readonly cache=.yarn_local_cache
@ -14,6 +18,17 @@ rm_cache
mkdir $cache
trap rm_cache EXIT
# We need to install `ng` but don't want to do it globally so we plate it into `.ng-cli` folder.
# This check prevents constant re-installing.
if [ ! -d ".ng-cli" ]; then
(
mkdir -p .ng-cli
cd .ng-cli
yarn add https://github.com/angular/cli-builds --cache-folder ../$cache
)
fi
./ng-cli-create.sh cli-hello-world
for testDir in $(ls | grep -v node_modules) ; do
[[ -d "$testDir" ]] || continue
echo "#################################"
@ -23,7 +38,17 @@ for testDir in $(ls | grep -v node_modules) ; do
cd $testDir
# Workaround for https://github.com/yarnpkg/yarn/issues/2256
rm -f yarn.lock
rm -rf dist
yarn install --cache-folder ../$cache
yarn test || exit 1
# Track payload size for cli-hello-world and hello_world__closure
if [[ $testDir == cli-hello-world ]] || [[ $testDir == hello_world__closure ]]; then
if [[ $testDir == cli-hello-world ]]; then
yarn build
fi
trackPayloadSize "$testDir" "dist/*.js" true false
fi
)
done
trackPayloadSize "umd" "../dist/packages-dist/*/bundles/*.umd.min.js" false false

View File

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

View File

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

View File

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

View File

@ -47,7 +47,8 @@ module.exports = function(config) {
pattern: 'packages/platform-browser/test/browser/static_assets/**',
included: false,
watched: false,
}
},
{pattern: 'packages/common/i18n/**', included: false, watched: false, served: true},
],
exclude: [

View File

@ -1,7 +1,18 @@
{
"name": "angular-srcs",
"version": "5.0.0-beta.0",
"version": "5.0.0-beta.4",
"dependencies": {
"@bazel/typescript": {
"version": "0.0.7",
"dependencies": {
"@types/node": {
"version": "7.0.18"
},
"tsickle": {
"version": "0.23.6"
}
}
},
"@types/angularjs": {
"version": "1.5.13-alpha"
},
@ -1542,7 +1553,7 @@
}
},
"cldr": {
"version": "3.5.2",
"version": "4.5.0",
"dependencies": {
"uglify-js": {
"version": "1.3.3"
@ -1552,6 +1563,59 @@
}
}
},
"cldr-data-downloader": {
"version": "0.3.2",
"dependencies": {
"adm-zip": {
"version": "0.4.4"
},
"async": {
"version": "2.5.0"
},
"bl": {
"version": "1.1.2"
},
"form-data": {
"version": "1.0.1"
},
"isarray": {
"version": "1.0.0"
},
"lodash": {
"version": "4.17.4"
},
"mime-db": {
"version": "1.27.0"
},
"mime-types": {
"version": "2.1.15"
},
"minimist": {
"version": "0.0.8"
},
"mkdirp": {
"version": "0.5.0"
},
"q": {
"version": "1.0.1"
},
"qs": {
"version": "6.2.3"
},
"readable-stream": {
"version": "2.0.6"
},
"request": {
"version": "2.74.0"
},
"tough-cookie": {
"version": "2.3.2"
}
}
},
"cldrjs": {
"version": "0.5.0"
},
"cli-boxes": {
"version": "1.0.0"
},
@ -1660,6 +1724,9 @@
}
}
},
"config-chain": {
"version": "1.1.11"
},
"configstore": {
"version": "2.1.0",
"dependencies": {
@ -3717,13 +3784,10 @@
"version": "0.3.0"
},
"memoizeasync": {
"version": "0.8.0",
"version": "1.0.0",
"dependencies": {
"lru-cache": {
"version": "2.5.0"
},
"passerror": {
"version": "0.0.2"
}
}
},
@ -3876,6 +3940,14 @@
"normalize-path": {
"version": "2.0.1"
},
"npmconf": {
"version": "2.0.9",
"dependencies": {
"semver": {
"version": "4.3.6"
}
}
},
"npmlog": {
"version": "4.0.2"
},
@ -4014,7 +4086,7 @@
"version": "2.0.0"
},
"passerror": {
"version": "0.0.1"
"version": "1.1.1"
},
"path-browserify": {
"version": "0.0.0"
@ -4081,6 +4153,9 @@
"process-nextick-args": {
"version": "1.0.6"
},
"progress": {
"version": "1.1.8"
},
"promise": {
"version": "7.1.1"
},
@ -4095,6 +4170,9 @@
}
}
},
"proto-list": {
"version": "1.2.4"
},
"protobufjs": {
"version": "5.0.0",
"dependencies": {
@ -4342,6 +4420,9 @@
"request-capture-har": {
"version": "1.1.4"
},
"request-progress": {
"version": "0.3.1"
},
"requires-port": {
"version": "1.0.0"
},
@ -4760,6 +4841,9 @@
"text-extensions": {
"version": "1.3.3"
},
"throttleit": {
"version": "0.0.2"
},
"through": {
"version": "2.3.8"
},
@ -4932,6 +5016,9 @@
"uglify-to-browserify": {
"version": "1.0.2"
},
"uid-number": {
"version": "0.0.5"
},
"uid-safe": {
"version": "2.0.0"
},
@ -5271,13 +5358,13 @@
"version": "8.2.2"
},
"xmldom": {
"version": "0.1.19"
"version": "0.1.27"
},
"xmlhttprequest-ssl": {
"version": "1.5.1"
},
"xpath": {
"version": "0.0.7"
"version": "0.0.24"
},
"xtend": {
"version": "4.0.1"

183
npm-shrinkwrap.json generated
View File

@ -1,7 +1,24 @@
{
"name": "angular-srcs",
"version": "5.0.0-beta.0",
"version": "5.0.0-beta.4",
"dependencies": {
"@bazel/typescript": {
"version": "0.0.7",
"from": "@bazel/typescript@latest",
"resolved": "https://registry.npmjs.org/@bazel/typescript/-/typescript-0.0.7.tgz",
"dependencies": {
"@types/node": {
"version": "7.0.18",
"from": "@types/node@7.0.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.18.tgz"
},
"tsickle": {
"version": "0.23.6",
"from": "tsickle@0.23.6",
"resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.23.6.tgz"
}
}
},
"@types/angularjs": {
"version": "1.5.13-alpha",
"from": "@types/angularjs@latest",
@ -2408,9 +2425,9 @@
}
},
"cldr": {
"version": "3.5.2",
"from": "cldr@>=3.5.0 <4.0.0",
"resolved": "https://registry.npmjs.org/cldr/-/cldr-3.5.2.tgz",
"version": "4.5.0",
"from": "cldr@4.5.0",
"resolved": "https://registry.npmjs.org/cldr/-/cldr-4.5.0.tgz",
"dependencies": {
"uglify-js": {
"version": "1.3.3",
@ -2424,6 +2441,93 @@
}
}
},
"cldr-data-downloader": {
"version": "0.3.2",
"from": "cldr-data-downloader@>=0.3.0 <0.4.0",
"resolved": "https://registry.npmjs.org/cldr-data-downloader/-/cldr-data-downloader-0.3.2.tgz",
"dependencies": {
"adm-zip": {
"version": "0.4.4",
"from": "adm-zip@0.4.4",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz"
},
"async": {
"version": "2.5.0",
"from": "async@>=2.0.1 <3.0.0",
"resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz"
},
"bl": {
"version": "1.1.2",
"from": "bl@>=1.1.2 <1.2.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz"
},
"form-data": {
"version": "1.0.1",
"from": "form-data@>=1.0.0-rc4 <1.1.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz"
},
"isarray": {
"version": "1.0.0",
"from": "isarray@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
},
"lodash": {
"version": "4.17.4",
"from": "lodash@>=4.14.0 <5.0.0",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
},
"mime-db": {
"version": "1.27.0",
"from": "mime-db@>=1.27.0 <1.28.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz"
},
"mime-types": {
"version": "2.1.15",
"from": "mime-types@>=2.1.7 <2.2.0",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz"
},
"minimist": {
"version": "0.0.8",
"from": "minimist@0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
},
"mkdirp": {
"version": "0.5.0",
"from": "mkdirp@0.5.0",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz"
},
"q": {
"version": "1.0.1",
"from": "q@1.0.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.0.1.tgz"
},
"qs": {
"version": "6.2.3",
"from": "qs@>=6.2.0 <6.3.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz"
},
"readable-stream": {
"version": "2.0.6",
"from": "readable-stream@>=2.0.5 <2.1.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz"
},
"request": {
"version": "2.74.0",
"from": "request@>=2.74.0 <2.75.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.74.0.tgz"
},
"tough-cookie": {
"version": "2.3.2",
"from": "tough-cookie@>=2.3.0 <2.4.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz"
}
}
},
"cldrjs": {
"version": "0.5.0",
"from": "cldrjs@0.5.0",
"resolved": "https://registry.npmjs.org/cldrjs/-/cldrjs-0.5.0.tgz"
},
"cli-boxes": {
"version": "1.0.0",
"from": "cli-boxes@>=1.0.0 <2.0.0",
@ -2596,6 +2700,11 @@
}
}
},
"config-chain": {
"version": "1.1.11",
"from": "config-chain@>=1.1.8 <1.2.0",
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz"
},
"configstore": {
"version": "2.1.0",
"from": "configstore@>=2.0.0 <3.0.0",
@ -5917,19 +6026,14 @@
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
},
"memoizeasync": {
"version": "0.8.0",
"from": "memoizeasync@0.8.0",
"resolved": "https://registry.npmjs.org/memoizeasync/-/memoizeasync-0.8.0.tgz",
"version": "1.0.0",
"from": "memoizeasync@1.0.0",
"resolved": "https://registry.npmjs.org/memoizeasync/-/memoizeasync-1.0.0.tgz",
"dependencies": {
"lru-cache": {
"version": "2.5.0",
"from": "lru-cache@2.5.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz"
},
"passerror": {
"version": "0.0.2",
"from": "passerror@0.0.2",
"resolved": "https://registry.npmjs.org/passerror/-/passerror-0.0.2.tgz"
}
}
},
@ -6176,6 +6280,18 @@
"from": "normalize-path@>=2.0.1 <3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz"
},
"npmconf": {
"version": "2.0.9",
"from": "npmconf@2.0.9",
"resolved": "https://registry.npmjs.org/npmconf/-/npmconf-2.0.9.tgz",
"dependencies": {
"semver": {
"version": "4.3.6",
"from": "semver@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0||>=4.0.0 <5.0.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
}
}
},
"npmlog": {
"version": "4.0.2",
"from": "npmlog@>=0.0.0 <1.0.0||>=1.0.0 <2.0.0||>=2.0.0 <3.0.0||>=3.0.0 <4.0.0||>=4.0.0 <5.0.0",
@ -6400,9 +6516,9 @@
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.0.tgz"
},
"passerror": {
"version": "0.0.1",
"from": "passerror@0.0.1",
"resolved": "https://registry.npmjs.org/passerror/-/passerror-0.0.1.tgz"
"version": "1.1.1",
"from": "passerror@1.1.1",
"resolved": "https://registry.npmjs.org/passerror/-/passerror-1.1.1.tgz"
},
"path-browserify": {
"version": "0.0.0",
@ -6511,6 +6627,11 @@
"from": "process-nextick-args@>=1.0.6 <1.1.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz"
},
"progress": {
"version": "1.1.8",
"from": "progress@1.1.8",
"resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz"
},
"promise": {
"version": "7.1.1",
"from": "promise@>=7.0.3 <8.0.0",
@ -6533,6 +6654,11 @@
}
}
},
"proto-list": {
"version": "1.2.4",
"from": "proto-list@>=1.2.1 <1.3.0",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz"
},
"protobufjs": {
"version": "5.0.0",
"from": "protobufjs@5.0.0",
@ -6934,6 +7060,11 @@
"from": "request-capture-har@>=1.1.4 <2.0.0",
"resolved": "https://registry.npmjs.org/request-capture-har/-/request-capture-har-1.1.4.tgz"
},
"request-progress": {
"version": "0.3.1",
"from": "request-progress@0.3.1",
"resolved": "https://registry.npmjs.org/request-progress/-/request-progress-0.3.1.tgz"
},
"requires-port": {
"version": "1.0.0",
"from": "requires-port@>=1.0.0 <2.0.0",
@ -7604,6 +7735,11 @@
"from": "text-extensions@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.3.3.tgz"
},
"throttleit": {
"version": "0.0.2",
"from": "throttleit@>=0.0.2 <0.1.0",
"resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz"
},
"through": {
"version": "2.3.8",
"from": "through@>=2.2.7 <3.0.0",
@ -7880,6 +8016,11 @@
"from": "uglify-to-browserify@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz"
},
"uid-number": {
"version": "0.0.5",
"from": "uid-number@0.0.5",
"resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.5.tgz"
},
"uid-safe": {
"version": "2.0.0",
"from": "uid-safe@>=2.0.0 <2.1.0",
@ -8427,9 +8568,9 @@
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz"
},
"xmldom": {
"version": "0.1.19",
"from": "xmldom@0.1.19",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.19.tgz"
"version": "0.1.27",
"from": "xmldom@0.1.27",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz"
},
"xmlhttprequest-ssl": {
"version": "1.5.1",
@ -8437,9 +8578,9 @@
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.1.tgz"
},
"xpath": {
"version": "0.0.7",
"from": "xpath@0.0.7",
"resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.7.tgz"
"version": "0.0.24",
"from": "xpath@0.0.24",
"resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.24.tgz"
},
"xtend": {
"version": "4.0.1",

View File

@ -31,6 +31,7 @@
"fsevents": "^1.0.14"
},
"devDependencies": {
"@bazel/typescript": "0.0.7",
"@types/angularjs": "^1.5.13-alpha",
"@types/base64-js": "^1.2.5",
"@types/fs-extra": "0.0.22-alpha",
@ -48,7 +49,9 @@
"canonical-path": "0.0.2",
"chokidar": "^1.1.0",
"clang-format": "^1.0.32",
"cldr": "^3.5.2",
"cldr": "^4.5.0",
"cldr-data-downloader": "^0.3.2",
"cldrjs": "^0.5.0",
"conventional-changelog": "^1.1.0",
"cors": "^2.7.1",
"dgeni": "^0.4.2",
@ -78,7 +81,6 @@
"nan": "^2.4.0",
"node-uuid": "1.4.x",
"parse5": "^3.0.1",
"protobufjs": "^5.0.0",
"protractor": "^4.0.14",
"react": "^0.14.0",
"rewire": "^2.3.3",

View File

@ -20,7 +20,7 @@ export class Animation {
private _animationAst: Ast;
constructor(private _driver: AnimationDriver, input: AnimationMetadata|AnimationMetadata[]) {
const errors: any[] = [];
const ast = buildAnimationAst(input, errors);
const ast = buildAnimationAst(_driver, input, errors);
if (errors.length) {
const errorMessage = `animation validation failed:\n${errors.join("\n")}`;
throw new Error(errorMessage);

View File

@ -7,6 +7,7 @@
*/
import {AUTO_STYLE, AnimateTimings, AnimationAnimateChildMetadata, AnimationAnimateMetadata, AnimationAnimateRefMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationQueryMetadata, AnimationQueryOptions, AnimationReferenceMetadata, AnimationSequenceMetadata, AnimationStaggerMetadata, AnimationStateMetadata, AnimationStyleMetadata, AnimationTransitionMetadata, AnimationTriggerMetadata, style, ɵStyleData} from '@angular/animations';
import {AnimationDriver} from '../render/animation_driver';
import {getOrSetAsInMap} from '../render/shared';
import {ENTER_SELECTOR, LEAVE_SELECTOR, NG_ANIMATING_SELECTOR, NG_TRIGGER_SELECTOR, SUBSTITUTION_EXPR_START, copyObj, extractStyleParams, iteratorToArray, normalizeAnimationEntry, resolveTiming, validateStyleParams} from '../util';
@ -54,8 +55,9 @@ const SELF_TOKEN_REGEX = new RegExp(`\s*${SELF_TOKEN}\s*,?`, 'g');
* Otherwise an error will be thrown.
*/
export function buildAnimationAst(
metadata: AnimationMetadata | AnimationMetadata[], errors: any[]): Ast {
return new AnimationAstBuilderVisitor().build(metadata, errors);
driver: AnimationDriver, metadata: AnimationMetadata | AnimationMetadata[],
errors: any[]): Ast {
return new AnimationAstBuilderVisitor(driver).build(metadata, errors);
}
const LEAVE_TOKEN = ':leave';
@ -65,6 +67,8 @@ const ENTER_TOKEN_REGEX = new RegExp(ENTER_TOKEN, 'g');
const ROOT_SELECTOR = '';
export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
constructor(private _driver: AnimationDriver) {}
build(metadata: AnimationMetadata|AnimationMetadata[], errors: any[]): Ast {
const context = new AnimationAstBuilderContext(errors);
this._resetContextStyleTimingState(context);
@ -273,6 +277,12 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
if (typeof tuple == 'string') return;
Object.keys(tuple).forEach(prop => {
if (!this._driver.validateStyleProperty(prop)) {
context.errors.push(
`The provided animation property "${prop}" is not a supported CSS property for animations`);
return;
}
const collectedStyles = context.collectedStyles[context.currentQuerySelector !];
const collectedEntry = collectedStyles[prop];
let updateCollectedStyle = true;

View File

@ -447,7 +447,7 @@ export class AnimationTimelineContext {
private _driver: AnimationDriver, public element: any,
public subInstructions: ElementInstructionMap, public errors: any[],
public timelines: TimelineBuilder[], initialTimeline?: TimelineBuilder) {
this.currentTimeline = initialTimeline || new TimelineBuilder(element, 0);
this.currentTimeline = initialTimeline || new TimelineBuilder(this._driver, element, 0);
timelines.push(this.currentTimeline);
}
@ -530,7 +530,7 @@ export class AnimationTimelineContext {
easing: ''
};
const builder = new SubTimelineBuilder(
instruction.element, instruction.keyframes, instruction.preStyleProps,
this._driver, instruction.element, instruction.keyframes, instruction.preStyleProps,
instruction.postStyleProps, updatedTimings, instruction.stretchStartingKeyframe);
this.timelines.push(builder);
return updatedTimings;
@ -582,7 +582,7 @@ export class TimelineBuilder {
private _currentEmptyStepKeyframe: ɵStyleData|null = null;
constructor(
public element: any, public startTime: number,
private _driver: AnimationDriver, public element: any, public startTime: number,
private _elementTimelineStylesLookup?: Map<any, ɵStyleData>) {
if (!this._elementTimelineStylesLookup) {
this._elementTimelineStylesLookup = new Map<any, ɵStyleData>();
@ -632,7 +632,7 @@ export class TimelineBuilder {
fork(element: any, currentTime?: number): TimelineBuilder {
this.applyStylesToKeyframe();
return new TimelineBuilder(
element, currentTime || this.currentTime, this._elementTimelineStylesLookup);
this._driver, element, currentTime || this.currentTime, this._elementTimelineStylesLookup);
}
private _loadKeyframe() {
@ -796,10 +796,10 @@ class SubTimelineBuilder extends TimelineBuilder {
public timings: AnimateTimings;
constructor(
public element: any, public keyframes: ɵStyleData[], public preStyleProps: string[],
public postStyleProps: string[], timings: AnimateTimings,
driver: AnimationDriver, public element: any, public keyframes: ɵStyleData[],
public preStyleProps: string[], public postStyleProps: string[], timings: AnimateTimings,
private _stretchStartingKeyframe: boolean = false) {
super(element, timings.delay);
super(driver, element, timings.delay);
this.timings = {duration: timings.duration, delay: timings.delay, easing: timings.easing};
}

View File

@ -7,13 +7,14 @@
*/
import {AnimationPlayer, NoopAnimationPlayer} from '@angular/animations';
import {containsElement, invokeQuery, matchesElement} from './shared';
import {containsElement, invokeQuery, matchesElement, validateStyleProperty} from './shared';
/**
* @experimental
*/
export class NoopAnimationDriver implements AnimationDriver {
validateStyleProperty(prop: string): boolean { return validateStyleProperty(prop); }
matchesElement(element: any, selector: string): boolean {
return matchesElement(element, selector);
}
@ -41,6 +42,8 @@ export class NoopAnimationDriver implements AnimationDriver {
export abstract class AnimationDriver {
static NOOP: AnimationDriver = new NoopAnimationDriver();
abstract validateStyleProperty(prop: string): boolean;
abstract matchesElement(element: any, selector: string): boolean;
abstract containsElement(elm1: any, elm2: any): boolean;

View File

@ -25,9 +25,9 @@ export class AnimationEngine {
// this method is designed to be overridden by the code that uses this engine
public onRemovalComplete = (element: any, context: any) => {};
constructor(driver: AnimationDriver, normalizer: AnimationStyleNormalizer) {
this._transitionEngine = new TransitionAnimationEngine(driver, normalizer);
this._timelineEngine = new TimelineAnimationEngine(driver, normalizer);
constructor(private _driver: AnimationDriver, normalizer: AnimationStyleNormalizer) {
this._transitionEngine = new TransitionAnimationEngine(_driver, normalizer);
this._timelineEngine = new TimelineAnimationEngine(_driver, normalizer);
this._transitionEngine.onRemovalComplete = (element: any, context: any) =>
this.onRemovalComplete(element, context);
@ -40,7 +40,8 @@ export class AnimationEngine {
let trigger = this._triggerCache[cacheKey];
if (!trigger) {
const errors: any[] = [];
const ast = buildAnimationAst(metadata as AnimationMetadata, errors) as TriggerAst;
const ast =
buildAnimationAst(this._driver, metadata as AnimationMetadata, errors) as TriggerAst;
if (errors.length) {
throw new Error(
`The animation trigger "${name}" has failed to build due to the following errors:\n - ${errors.join("\n - ")}`);

View File

@ -166,6 +166,21 @@ if (typeof Element != 'undefined') {
};
}
let _CACHED_BODY: {style: any}|null = null;
export function validateStyleProperty(prop: string): boolean {
if (!_CACHED_BODY) {
_CACHED_BODY = getBodyNode() || {};
}
return _CACHED_BODY !.style ? prop in _CACHED_BODY !.style : true;
}
export function getBodyNode(): any|null {
if (typeof document != 'undefined') {
return document.body;
}
return null;
}
export const matchesElement = _matches;
export const containsElement = _contains;
export const invokeQuery = _query;

View File

@ -28,7 +28,7 @@ export class TimelineAnimationEngine {
register(id: string, metadata: AnimationMetadata|AnimationMetadata[]) {
const errors: any[] = [];
const ast = buildAnimationAst(metadata, errors);
const ast = buildAnimationAst(this._driver, metadata, errors);
if (errors.length) {
throw new Error(
`Unable to build the animation due to the following errors: ${errors.join("\n")}`);

View File

@ -16,7 +16,7 @@ import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_sty
import {ENTER_CLASSNAME, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_SELECTOR, NG_TRIGGER_CLASSNAME, NG_TRIGGER_SELECTOR, copyObj, eraseStyles, setStyles} from '../util';
import {AnimationDriver} from './animation_driver';
import {getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared';
import {getBodyNode, getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared';
const QUEUED_CLASSNAME = 'ng-animate-queued';
const QUEUED_SELECTOR = '.ng-animate-queued';
@ -817,6 +817,7 @@ export class TransitionAnimationEngine {
const disabledElementsSet = new Set<any>();
this.disabledNodes.forEach(node => {
disabledElementsSet.add(node);
const nodesThatAreDisabled = this.driver.query(node, QUEUED_SELECTOR, true);
for (let i = 0; i < nodesThatAreDisabled.length; i++) {
disabledElementsSet.add(nodesThatAreDisabled[i]);
@ -960,22 +961,45 @@ export class TransitionAnimationEngine {
const element = player.element;
const previousPlayers =
this._getPreviousPlayers(element, false, player.namespaceId, player.triggerName, null);
previousPlayers.forEach(
prevPlayer => { getOrSetAsInMap(allPreviousPlayersMap, element, []).push(prevPlayer); });
previousPlayers.forEach(prevPlayer => {
getOrSetAsInMap(allPreviousPlayersMap, element, []).push(prevPlayer);
prevPlayer.destroy();
});
});
allPreviousPlayersMap.forEach(players => players.forEach(player => player.destroy()));
// PRE STAGE: fill the ! styles
const preStylesMap = allPreStyleElements.size ?
cloakAndComputeStyles(
this.driver, enterNodesWithoutAnimations, allPreStyleElements, PRE_STYLE) :
new Map<any, ɵStyleData>();
// this is a special case for nodes that will be removed (either by)
// having their own leave animations or by being queried in a container
// that will be removed once a parent animation is complete. The idea
// here is that * styles must be identical to ! styles because of
// backwards compatibility (* is also filled in by default in many places).
// Otherwise * styles will return an empty value or auto since the element
// that is being getComputedStyle'd will not be visible (since * = destination)
const replaceNodes = allLeaveNodes.filter(node => {
return replacePostStylesAsPre(node, allPreStyleElements, allPostStyleElements);
});
// POST STAGE: fill the * styles
const postStylesMap = cloakAndComputeStyles(
const [postStylesMap, allLeaveQueriedNodes] = cloakAndComputeStyles(
this.driver, leaveNodesWithoutAnimations, allPostStyleElements, AUTO_STYLE);
allLeaveQueriedNodes.forEach(node => {
if (replacePostStylesAsPre(node, allPreStyleElements, allPostStyleElements)) {
replaceNodes.push(node);
}
});
// PRE STAGE: fill the ! styles
const [preStylesMap] = allPreStyleElements.size ?
cloakAndComputeStyles(
this.driver, enterNodesWithoutAnimations, allPreStyleElements, PRE_STYLE) :
[new Map<any, ɵStyleData>()];
replaceNodes.forEach(node => {
const post = postStylesMap.get(node);
const pre = preStylesMap.get(node);
postStylesMap.set(node, { ...post, ...pre } as any);
});
const rootPlayers: TransitionAnimationPlayer[] = [];
const subPlayers: TransitionAnimationPlayer[] = [];
queuedInstructions.forEach(entry => {
@ -1015,11 +1039,20 @@ export class TransitionAnimationEngine {
} else {
eraseStyles(element, instruction.fromStyles);
player.onDestroy(() => setStyles(element, instruction.toStyles));
// there still might be a ancestor player animating this
// element therefore we will still add it as a sub player
// even if its animation may be disabled
subPlayers.push(player);
if (disabledElementsSet.has(element)) {
skippedPlayers.push(player);
}
}
});
// find all of the sub players' corresponding inner animation player
subPlayers.forEach(player => {
// even if any players are not found for a sub animation then it
// will still complete itself after the next tick since it's Noop
const playersForElement = skippedPlayersMap.get(player.element);
if (playersForElement && playersForElement.length) {
const innerPlayer = optimizeGroupPlayer(playersForElement);
@ -1051,7 +1084,7 @@ export class TransitionAnimationEngine {
// until that animation is over (or the parent queried animation)
if (details && details.hasAnimation) continue;
let players: AnimationPlayer[] = [];
let players: TransitionAnimationPlayer[] = [];
// if this element is queried or if it contains queried children
// then we want for the element not to be removed from the page
@ -1070,8 +1103,10 @@ export class TransitionAnimationEngine {
}
}
}
if (players.length) {
removeNodesAfterAnimationDone(this, element, players);
const activePlayers = players.filter(p => !p.destroyed);
if (activePlayers.length) {
removeNodesAfterAnimationDone(this, element, activePlayers);
} else {
this.processLeaveNode(element);
}
@ -1141,10 +1176,6 @@ export class TransitionAnimationEngine {
private _beforeAnimationBuild(
namespaceId: string, instruction: AnimationTransitionInstruction,
allPreviousPlayersMap: Map<any, TransitionAnimationPlayer[]>) {
// it's important to do this step before destroying the players
// so that the onDone callback below won't fire before this
eraseStyles(instruction.element, instruction.fromStyles);
const triggerName = instruction.triggerName;
const rootElement = instruction.element;
@ -1166,9 +1197,14 @@ export class TransitionAnimationEngine {
if (realPlayer.beforeDestroy) {
realPlayer.beforeDestroy();
}
player.destroy();
players.push(player);
});
});
// this needs to be done so that the PRE/POST styles can be
// computed properly without interfering with the previous animation
eraseStyles(rootElement, instruction.fromStyles);
}
private _buildAnimation(
@ -1400,9 +1436,10 @@ function cloakElement(element: any, value?: string) {
function cloakAndComputeStyles(
driver: AnimationDriver, elements: any[], elementPropsMap: Map<any, Set<string>>,
defaultStyle: string): Map<any, ɵStyleData> {
defaultStyle: string): [Map<any, ɵStyleData>, any[]] {
const cloakVals = elements.map(element => cloakElement(element));
const valuesMap = new Map<any, ɵStyleData>();
const failedElements: any[] = [];
elementPropsMap.forEach((props: Set<string>, element: any) => {
const styles: ɵStyleData = {};
@ -1413,13 +1450,14 @@ function cloakAndComputeStyles(
// by a parent animation element being detached.
if (!value || value.length == 0) {
element[REMOVAL_FLAG] = NULL_REMOVED_QUERIED_STATE;
failedElements.push(element);
}
});
valuesMap.set(element, styles);
});
elements.forEach((element, i) => cloakElement(element, cloakVals[i]));
return valuesMap;
return [valuesMap, failedElements];
}
/*
@ -1487,13 +1525,6 @@ function removeClass(element: any, className: string) {
}
}
function getBodyNode(): any|null {
if (typeof document != 'undefined') {
return document.body;
}
return null;
}
function removeNodesAfterAnimationDone(
engine: TransitionAnimationEngine, element: any, players: AnimationPlayer[]) {
optimizeGroupPlayer(players).onDone(() => engine.processLeaveNode(element));
@ -1526,3 +1557,20 @@ function objEquals(a: {[key: string]: any}, b: {[key: string]: any}): boolean {
}
return true;
}
function replacePostStylesAsPre(
element: any, allPreStyleElements: Map<any, Set<string>>,
allPostStyleElements: Map<any, Set<string>>): boolean {
const postEntry = allPostStyleElements.get(element);
if (!postEntry) return false;
let preEntry = allPreStyleElements.get(element);
if (preEntry) {
postEntry.forEach(data => preEntry !.add(data));
} else {
allPreStyleElements.set(element, postEntry);
}
allPostStyleElements.delete(element);
return true;
}

View File

@ -8,11 +8,13 @@
import {AnimationPlayer, ɵStyleData} from '@angular/animations';
import {AnimationDriver} from '../animation_driver';
import {containsElement, invokeQuery, matchesElement} from '../shared';
import {containsElement, invokeQuery, matchesElement, validateStyleProperty} from '../shared';
import {WebAnimationsPlayer} from './web_animations_player';
export class WebAnimationsDriver implements AnimationDriver {
validateStyleProperty(prop: string): boolean { return validateStyleProperty(prop); }
matchesElement(element: any, selector: string): boolean {
return matchesElement(element, selector);
}

View File

@ -158,9 +158,9 @@ export class WebAnimationsPlayer implements AnimationPlayer {
destroy(): void {
if (!this._destroyed) {
this._destroyed = true;
this._resetDomPlayerState();
this._onFinish();
this._destroyed = true;
this._onDestroyFns.forEach(fn => fn());
this._onDestroyFns = [];
}

View File

@ -177,10 +177,12 @@ export function main() {
it('should throw if dynamic style substitutions are used without defaults within state() definitions',
() => {
const steps = [state('final', style({
'width': '{{ one }}px',
'borderRadius': '{{ two }}px {{ three }}px',
}))];
const steps = [
state('final', style({
'width': '{{ one }}px',
'borderRadius': '{{ two }}px {{ three }}px',
})),
];
expect(() => { validateAndThrowAnimationSequence(steps); })
.toThrowError(
@ -198,6 +200,14 @@ export function main() {
.toThrowError(
/state\("panfinal", ...\) must define default values for all the following style substitutions: greyColor/);
});
it('should throw an error if an invalid CSS property is used in the animation', () => {
const steps = [animate(1000, style({abc: '500px'}))];
expect(() => { validateAndThrowAnimationSequence(steps); })
.toThrowError(
/The provided animation property "abc" is not a supported CSS property for animations/);
});
});
describe('keyframe building', () => {
@ -388,14 +398,13 @@ export function main() {
it('should allow multiple substitutions to occur within the same style value', () => {
const steps = [
style({transform: ''}),
animate(1000, style({transform: 'translateX({{ x }}) translateY({{ y }})'}))
style({borderRadius: '100px 100px'}),
animate(1000, style({borderRadius: '{{ one }}px {{ two }}'})),
];
const players =
invokeAnimationSequence(rootElement, steps, buildParams({x: '200px', y: '400px'}));
invokeAnimationSequence(rootElement, steps, buildParams({one: '200', two: '400px'}));
expect(players[0].keyframes).toEqual([
{offset: 0, transform: ''},
{offset: 1, transform: 'translateX(200px) translateY(400px)'}
{offset: 0, borderRadius: '100px 100px'}, {offset: 1, borderRadius: '200px 400px'}
]);
});
@ -571,18 +580,12 @@ export function main() {
() => {
const steps = [
animate(1000, style({height: '50px'})),
animate(
2000, keyframes([
style({left: '0', transform: 'rotate(0deg)', offset: 0}),
style({
left: '40%',
transform: 'rotate(250deg) translateY(-200px)',
offset: .33
}),
style(
{left: '60%', transform: 'rotate(180deg) translateY(200px)', offset: .66}),
style({left: 'calc(100% - 100px)', transform: 'rotate(0deg)', offset: 1}),
])),
animate(2000, keyframes([
style({left: '0', top: '0', offset: 0}),
style({left: '40%', top: '50%', offset: .33}),
style({left: '60%', top: '80%', offset: .66}),
style({left: 'calc(100% - 100px)', top: '100%', offset: 1}),
])),
group([animate('2s', style({width: '200px'}))]),
animate('2s', style({height: '300px'})),
group([animate('2s', style({height: '500px', width: '500px'}))])
@ -987,8 +990,9 @@ function invokeAnimationSequence(
}
function validateAndThrowAnimationSequence(steps: AnimationMetadata | AnimationMetadata[]) {
const driver = new MockAnimationDriver();
const errors: any[] = [];
const ast = buildAnimationAst(steps, errors);
const ast = buildAnimationAst(driver, steps, errors);
if (errors.length) {
throw new Error(errors.join('\n'));
}

View File

@ -411,8 +411,10 @@ export function main() {
() => {
const engine = makeEngine();
const trig = trigger('something', [
state('x', style({opacity: 0})), state('y', style({opacity: .5})),
state('z', style({opacity: 1})), transition('* => *', animate(1000))
state('x', style({opacity: 0})),
state('y', style({opacity: .5})),
state('z', style({opacity: 1})),
transition('* => *', animate(1000)),
]);
registerTrigger(element, engine, trig);
@ -428,7 +430,7 @@ export function main() {
const player2 = engine.players[0];
expect(parseFloat(element.style.opacity)).toEqual(.5);
expect(parseFloat(element.style.opacity)).not.toEqual(.5);
player2.finish();
expect(parseFloat(element.style.opacity)).toEqual(1);
@ -655,8 +657,9 @@ function registerTrigger(
element: any, engine: TransitionAnimationEngine, metadata: AnimationTriggerMetadata,
id: string = DEFAULT_NAMESPACE_ID) {
const errors: any[] = [];
const driver = new MockAnimationDriver();
const name = metadata.name;
const ast = buildAnimationAst(metadata as AnimationMetadata, errors) as TriggerAst;
const ast = buildAnimationAst(driver, metadata as AnimationMetadata, errors) as TriggerAst;
if (errors.length) {
}
const trigger = buildTrigger(name, ast);

View File

@ -11,12 +11,14 @@ import {trigger} from '@angular/animations';
import {TriggerAst} from '../src/dsl/animation_ast';
import {buildAnimationAst} from '../src/dsl/animation_ast_builder';
import {AnimationTrigger, buildTrigger} from '../src/dsl/animation_trigger';
import {MockAnimationDriver} from '../testing/src/mock_animation_driver';
export function makeTrigger(
name: string, steps: any, skipErrors: boolean = false): AnimationTrigger {
const driver = new MockAnimationDriver();
const errors: any[] = [];
const triggerData = trigger(name, steps);
const triggerAst = buildAnimationAst(triggerData, errors) as TriggerAst;
const triggerAst = buildAnimationAst(driver, triggerData, errors) as TriggerAst;
if (!skipErrors && errors.length) {
const LINE_START = '\n - ';
throw new Error(

View File

@ -8,15 +8,18 @@
import {AUTO_STYLE, AnimationPlayer, NoopAnimationPlayer, ɵStyleData} from '@angular/animations';
import {AnimationDriver} from '../../src/render/animation_driver';
import {containsElement, invokeQuery, matchesElement} from '../../src/render/shared';
import {containsElement, invokeQuery, matchesElement, validateStyleProperty} from '../../src/render/shared';
import {allowPreviousPlayerStylesMerge} from '../../src/util';
/**
* @experimental Animation support is experimental.
*/
export class MockAnimationDriver implements AnimationDriver {
static log: AnimationPlayer[] = [];
validateStyleProperty(prop: string): boolean { return validateStyleProperty(prop); }
matchesElement(element: any, selector: string): boolean {
return matchesElement(element, selector);
}

View File

@ -282,11 +282,12 @@ export interface AnimationStaggerMetadata extends AnimationMetadata {
* <div [@myAnimationTrigger]="myStatusExp">...</div>
* ```
*
* ## Disable Child Animations
* ## Disable Animations
* A special animation control binding called `@.disabled` can be placed on an element which will
then disable animations for any inner animation triggers situated within the element.
then disable animations for any inner animation triggers situated within the element as well as
any animations on the element itself.
*
* When true, the `@.disabled` binding will prevent inner animations from rendering. The example
* When true, the `@.disabled` binding will prevent all animations from rendering. The example
below shows how to use this feature:
*
* ```ts
@ -312,8 +313,8 @@ export interface AnimationStaggerMetadata extends AnimationMetadata {
* The `@childAnimation` trigger will not animate because `@.disabled` prevents it from happening
(when true).
*
* Note that `@.disbled` will only disable inner animations (any animations running on the same
element will not be disabled).
* Note that `@.disbled` will only disable all animations (this means any animations running on
* the same element will also be disabled).
*
* ### Disabling Animations Application-wide
* When an area of the template is set to have animations disabled, **all** inner components will

View File

@ -0,0 +1 @@
# Empty marker file, indicating this directory is a Bazel package.

9
packages/bazel/WORKSPACE Normal file
View File

@ -0,0 +1,9 @@
# By convention, the name should "describe the project in reverse-DNS form"
# https://docs.bazel.build/versions/master/be/functions.html#workspace
# But if we use "io_angular" then the loads used in BUILD files will
# be unfamiliar to Angular users who import from '@angular/pkg' in
# TypeScript files. We want to reduce the impedance between the Bazel
# and node naming schemes.
# We take the name "angular" so that users can write
# load("@angular//:index.bzl", "ng_module")
workspace(name = "angular")

9
packages/bazel/index.bzl Normal file
View File

@ -0,0 +1,9 @@
# 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
""" Public API surface is re-exported here.
Users should not load files under "/src"
"""
load("//src:ng_module.bzl", "ng_module")

View File

@ -0,0 +1,15 @@
{
"name": "@angular/bazel",
"version": "0.0.0-PLACEHOLDER",
"description": "Angular - bazel build rules",
"author": "angular",
"license": "MIT",
"peerDependencies": {
"@angular/compiler-cli": "0.0.0-PLACEHOLDER",
"typescript": "~2.3"
},
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.git"
}
}

View File

@ -0,0 +1 @@
# Empty marker file, indicating this directory is a Bazel package.

View File

@ -0,0 +1,192 @@
# 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
load(":rules_typescript.bzl",
"tsc_wrapped_tsconfig",
"COMMON_ATTRIBUTES",
"compile_ts",
"DEPS_ASPECTS",
"ts_providers_dict_to_struct",
"json_marshal",
)
# Calculate the expected output of the template compiler for every source in
# in the library. Most of these will be produced as empty files but it is
# unknown, without parsing, which will be empty.
def _expected_outs(ctx, label):
devmode_js_files = []
closure_js_files = []
declaration_files = []
summary_files = []
codegen_inputs = ctx.files.srcs
for src in ctx.files.srcs + ctx.files.assets:
if src.short_path.endswith(".ts") and not src.short_path.endswith(".d.ts"):
basename = src.short_path[len(ctx.label.package) + 1:-len(".ts")]
devmode_js = [
".ngfactory.js",
".ngsummary.js",
".js",
]
summaries = [".ngsummary.json"]
elif src.short_path.endswith(".css"):
basename = src.short_path[len(ctx.label.package) + 1:-len(".css")]
devmode_js = [
".css.shim.ngstyle.js",
".css.ngstyle.js",
]
summaries = []
closure_js = [f.replace(".js", ".closure.js") for f in devmode_js]
declarations = [f.replace(".js", ".d.ts") for f in devmode_js]
devmode_js_files += [ctx.new_file(ctx.bin_dir, basename + ext) for ext in devmode_js]
closure_js_files += [ctx.new_file(ctx.bin_dir, basename + ext) for ext in closure_js]
declaration_files += [ctx.new_file(ctx.bin_dir, basename + ext) for ext in declarations]
summary_files += [ctx.new_file(ctx.bin_dir, basename + ext) for ext in summaries]
return struct(
closure_js = closure_js_files,
devmode_js = devmode_js_files,
declarations = declaration_files,
summaries = summary_files,
)
def _ngc_tsconfig(ctx, files, srcs, **kwargs):
outs = _expected_outs(ctx, ctx.label)
if "devmode_manifest" in kwargs:
expected_outs = outs.devmode_js + outs.declarations + outs.summaries
else:
expected_outs = outs.closure_js
return dict(tsc_wrapped_tsconfig(ctx, files, srcs, **kwargs), **{
"angularCompilerOptions": {
"generateCodeForLibraries": False,
# FIXME: wrong place to de-dupe
"expectedOut": depset([o.path for o in expected_outs]).to_list()
}
})
def _collect_summaries_aspect_impl(target, ctx):
results = target.angular.summaries if hasattr(target, "angular") else depset()
# If we are visiting empty-srcs ts_library, this is a re-export
srcs = target.srcs if hasattr(target, "srcs") else []
# "re-export" rules should expose all the files of their deps
if not srcs:
for dep in ctx.rule.attr.deps:
if (hasattr(dep, "angular")):
results += dep.angular.summaries
return struct(collect_summaries_aspect_result = results)
_collect_summaries_aspect = aspect(
implementation = _collect_summaries_aspect_impl,
attr_aspects = ["deps"],
)
def _compile_action(ctx, inputs, outputs, config_file_path):
summaries = depset()
for dep in ctx.attr.deps:
if hasattr(dep, "collect_summaries_aspect_result"):
summaries += dep.collect_summaries_aspect_result
action_inputs = inputs + summaries.to_list() + ctx.files.assets
# print("ASSETS", [a.path for a in ctx.files.assets])
# print("INPUTS", ctx.label, [o.path for o in summaries if o.path.find("core/src") > 0])
if hasattr(ctx.attr, "node_modules"):
action_inputs += [f for f in ctx.files.node_modules
if f.path.endswith(".ts") or f.path.endswith(".json")]
if hasattr(ctx.attr, "tsconfig") and ctx.file.tsconfig:
action_inputs += [ctx.file.tsconfig]
# One at-sign makes this a params-file, enabling the worker strategy.
# Two at-signs escapes the argument so it's passed through to ngc
# rather than the contents getting expanded.
if ctx.attr._supports_workers:
arguments = ["@@" + config_file_path]
else:
arguments = ["-p", config_file_path]
ctx.action(
progress_message = "Compiling Angular templates (ngc) %s" % ctx.label,
mnemonic = "AngularTemplateCompile",
inputs = action_inputs,
outputs = outputs,
arguments = arguments,
executable = ctx.executable.compiler,
execution_requirements = {
"supports-workers": str(int(ctx.attr._supports_workers)),
},
)
def _prodmode_compile_action(ctx, inputs, outputs, config_file_path):
outs = _expected_outs(ctx, ctx.label)
_compile_action(ctx, inputs, outputs + outs.closure_js, config_file_path)
def _devmode_compile_action(ctx, inputs, outputs, config_file_path):
outs = _expected_outs(ctx, ctx.label)
_compile_action(ctx, inputs, outputs + outs.devmode_js + outs.declarations + outs.summaries, config_file_path)
def ng_module_impl(ctx, ts_compile_actions):
providers = ts_compile_actions(
ctx, is_library=True, compile_action=_prodmode_compile_action,
devmode_compile_action=_devmode_compile_action,
tsc_wrapped_tsconfig=_ngc_tsconfig,
outputs = _expected_outs)
#addl_declarations = [_expected_outs(ctx)]
#providers["typescript"]["declarations"] += addl_declarations
#providers["typescript"]["transitive_declarations"] += addl_declarations
providers["angular"] = {
"summaries": _expected_outs(ctx, ctx.label).summaries
}
return providers
def _ng_module_impl(ctx):
return ts_providers_dict_to_struct(ng_module_impl(ctx, compile_ts))
NG_MODULE_ATTRIBUTES = {
"srcs": attr.label_list(allow_files = [".ts"]),
"deps": attr.label_list(aspects = DEPS_ASPECTS + [_collect_summaries_aspect]),
"assets": attr.label_list(allow_files = [
".css",
# TODO(alexeagle): change this to ".ng.html" when usages updated
".html",
]),
# TODO(alexeagle): wire up when we have i18n in bazel
"no_i18n": attr.bool(default = False),
"compiler": attr.label(
default = Label("//src/ngc-wrapped"),
executable = True,
cfg = "host",
),
# TODO(alexeagle): enable workers for ngc
"_supports_workers": attr.bool(default = False),
}
ng_module = rule(
implementation = _ng_module_impl,
attrs = COMMON_ATTRIBUTES + NG_MODULE_ATTRIBUTES + {
"tsconfig": attr.label(allow_files = True, single_file = True),
# @// is special syntax for the "main" repository
# The default assumes the user specified a target "node_modules" in their
# root BUILD file.
"node_modules": attr.label(
default = Label("@//:node_modules")
),
},
)

View File

@ -0,0 +1,27 @@
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
load("@build_bazel_rules_typescript//:defs.bzl", "ts_library")
licenses(["notice"]) # Apache 2.0
ts_library(
name = "ngc_lib",
srcs = ["index.ts"],
deps = [
# BEGIN-INTERNAL
# Only needed when compiling within the Angular repo.
# Users will get this dependency from node_modules.
"@//packages/compiler-cli",
# END-INTERNAL
"@build_bazel_rules_typescript//internal/tsc_wrapped"
],
tsconfig = ":tsconfig.json",
)
nodejs_binary(
name = "ngc-wrapped",
# Entry point assumes the user is outside this WORKSPACE,
# and references our rules with @angular//src/ngc-wrapped
entry_point = "angular/src/ngc-wrapped/index.js",
data = [":ngc_lib"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,3 @@
# ngc-wrapped
This is a wrapper around @angular/compiler-cli that makes ngc run under Bazel.

View File

@ -0,0 +1,187 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ng from '@angular/compiler-cli';
import {CompilerHost, UncachedFileLoader, parseTsconfig} from '@bazel/typescript';
import * as fs from 'fs';
import * as path from 'path';
import * as tsickle from 'tsickle';
import * as ts from 'typescript';
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
// FIXME: we should be able to add the assets to the tsconfig so FileLoader
// knows about them
const NGC_NON_TS_INPUTS =
/(\.(ngsummary|ngstyle|ngfactory)(\.d)?\.ts|\.ngsummary\.json|\.css|\.html)$/;
// FIXME should need only summary, css, html
function topologicalSort(
result: tsickle.FileMap<boolean>, current: string, modulesManifest: tsickle.ModulesManifest,
visiting: tsickle.FileMap<boolean>) {
const referencedModules = modulesManifest.getReferencedModules(current);
if (!referencedModules) return; // not in the local set of sources.
for (const referencedModule of referencedModules) {
const referencedFileName = modulesManifest.getFileNameFromModule(referencedModule);
if (!referencedFileName) continue; // Ambient modules.
if (!result[referencedFileName]) {
if (visiting[referencedFileName]) {
const path = current + ' -> ' + Object.keys(visiting).join(' -> ');
throw new Error('Cyclical dependency between files:\n' + path);
}
visiting[referencedFileName] = true;
topologicalSort(result, referencedFileName, modulesManifest, visiting);
delete visiting[referencedFileName];
}
}
result[current] = true;
}
// TODO(alexeagle): move to tsc-wrapped in third_party so it's shared
export function constructManifest(
modulesManifest: tsickle.ModulesManifest,
host: {flattenOutDir: (f: string) => string}): string {
const result: tsickle.FileMap<boolean> = {};
for (const file of modulesManifest.fileNames) {
topologicalSort(result, file, modulesManifest, {});
}
// NB: The object literal maintains insertion order.
return Object.keys(result).map(fn => host.flattenOutDir(fn)).join('\n') + '\n';
}
export function main(args) {
const project = args[1];
const [{options: tsOptions, bazelOpts, files, config}] = parseTsconfig(project);
const {basePath} = ng.calcProjectFileAndBasePath(project);
const ngOptions = ng.createNgCompilerOptions(basePath, config, tsOptions);
if (!bazelOpts.es5Mode) {
ngOptions.annotateForClosureCompiler = true;
ngOptions.annotationsAs = 'static fields';
}
function relativeToRootDir(filePath: string): string {
if (tsOptions.rootDir) {
const rel = path.relative(tsOptions.rootDir, filePath);
if (rel.indexOf('.') != 0) return rel;
}
return filePath;
}
const expectedOuts = [...config['angularCompilerOptions']['expectedOut']];
const tsHost = ts.createCompilerHost(tsOptions, true);
const originalWriteFile = tsHost.writeFile.bind(tsHost);
tsHost.writeFile =
(fileName: string, content: string, writeByteOrderMark: boolean,
onError?: (message: string) => void, sourceFiles?: ts.SourceFile[]) => {
const relative = relativeToRootDir(fileName);
const expectedIdx = expectedOuts.findIndex(o => o === relative);
if (expectedIdx >= 0) {
expectedOuts.splice(expectedIdx, 1);
originalWriteFile(fileName, content, writeByteOrderMark, onError, sourceFiles);
}
};
// Patch fileExists when resolving modules, so that ngc can ask TypeScript to
// resolve non-existing generated files that don't exist on disk, but are
// synthetic and added to the `programWithStubs` based on real inputs.
const generatedFileModuleResolverHost = Object.create(tsHost);
generatedFileModuleResolverHost.fileExists = (fileName: string) => {
const match = /^(.*?)\.(ngfactory|ngsummary|ngstyle|shim\.ngstyle)(.*)$/.exec(fileName);
if (match) {
const [, file, suffix, ext] = match;
// Performance: skip looking for files other than .d.ts or .ts
if (ext !== '.ts' && ext !== '.d.ts') return false;
if (suffix.indexOf('ngstyle') >= 0) {
// Look for foo.css on disk
fileName = file;
} else {
// Look for foo.d.ts or foo.ts on disk
fileName = file + (ext || '');
}
}
return tsHost.fileExists(fileName);
};
function generatedFileModuleResolver(
moduleName: string, containingFile: string,
compilerOptions: ts.CompilerOptions): ts.ResolvedModuleWithFailedLookupLocations {
return ts.resolveModuleName(
moduleName, containingFile, compilerOptions, generatedFileModuleResolverHost);
}
const bazelHost = new CompilerHost(
files, tsOptions, bazelOpts, tsHost, new UncachedFileLoader(), generatedFileModuleResolver);
bazelHost.allowNonHermeticRead = (filePath: string) =>
NGC_NON_TS_INPUTS.test(filePath) || filePath.split(path.sep).indexOf('node_modules') != -1;
bazelHost.shouldSkipTsickleProcessing = (fileName: string): boolean =>
bazelOpts.compilationTargetSrc.indexOf(fileName) === -1 && !NGC_NON_TS_INPUTS.test(fileName);
const ngHost = ng.createCompilerHost({options: ngOptions, tsHost: bazelHost});
ngHost.fileNameToModuleName = (importedFilePath: string, containingFilePath: string) =>
relativeToRootDir(importedFilePath).replace(EXT, '');
ngHost.toSummaryFileName = (fileName: string, referringSrcFileName: string) =>
ngHost.fileNameToModuleName(fileName, referringSrcFileName);
const tsickleOpts = {
googmodule: bazelOpts.googmodule,
es5Mode: bazelOpts.es5Mode,
prelude: bazelOpts.prelude,
untyped: bazelOpts.untyped,
typeBlackListPaths: new Set(bazelOpts.typeBlackListPaths),
transformDecorators: bazelOpts.tsickle,
transformTypesToClosure: bazelOpts.tsickle,
};
const emitCallback: ng.TsEmitCallback = ({
program,
targetSourceFile,
writeFile,
cancellationToken,
emitOnlyDtsFiles,
customTransformers = {},
}) =>
tsickle.emitWithTsickle(
program, bazelHost, tsickleOpts, bazelHost, ngOptions, targetSourceFile, writeFile,
cancellationToken, emitOnlyDtsFiles, {
beforeTs: customTransformers.before,
afterTs: customTransformers.after,
});
const {diagnostics, emitResult} =
ng.performCompilation({rootNames: files, options: ngOptions, host: ngHost, emitCallback});
const tsickleEmitResult = emitResult as tsickle.EmitResult;
let externs = '/** @externs */\n';
if (diagnostics.length) {
console.error(ng.formatDiagnostics(ngOptions, diagnostics));
} else {
if (bazelOpts.tsickleGenerateExterns) {
externs += tsickle.getGeneratedExterns(tsickleEmitResult.externs);
}
if (bazelOpts.manifest) {
const manifest = constructManifest(tsickleEmitResult.modulesManifest, bazelHost);
fs.writeFileSync(bazelOpts.manifest, manifest);
}
}
if (bazelOpts.tsickleExternsPath) {
// Note: when tsickleExternsPath is provided, we always write a file as a
// marker that compilation succeeded, even if it's empty (just containing an
// @externs).
fs.writeFileSync(bazelOpts.tsickleExternsPath, externs);
}
for (const missing of expectedOuts) {
originalWriteFile(missing, '', false);
}
return diagnostics.some(d => d.category === ts.DiagnosticCategory.Error) ? 1 : 0;
}
if (require.main === module) {
process.exitCode = main(process.argv.slice(2));
}

View File

@ -0,0 +1,5 @@
{
"compilerOptions": {
"lib": ["es5", "es2015.collection", "es2015.core"]
}
}

View File

@ -0,0 +1,9 @@
# Allows different paths for these imports in google3
load("@build_bazel_rules_typescript//internal:build_defs.bzl", "tsc_wrapped_tsconfig")
load(
"@build_bazel_rules_typescript//internal:common/compilation.bzl",
"COMMON_ATTRIBUTES", "compile_ts", "DEPS_ASPECTS", "ts_providers_dict_to_struct"
)
load("@build_bazel_rules_typescript//internal:common/json_marshal.bzl", "json_marshal")

View File

@ -5,6 +5,7 @@ ts_library(
name = "common",
srcs = glob(["**/*.ts"], exclude=[
"http/**",
"i18n/**",
"test/**",
"testing/**",
]),

View File

@ -0,0 +1,22 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['mn', 'o', 'm', 'a', 'n'],
['middernag', 'die oggend', 'die middag', 'die aand', 'die nag'],
],
[
['mn', 'o', 'm', 'a', 'n'],
['middernag', 'oggend', 'middag', 'aand', 'nag'],
],
['00:00', ['05:00', '12:00'], ['12:00', '18:00'], ['18:00', '24:00'], ['00:00', '05:00']]
];

View File

@ -0,0 +1,22 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['mn', 'o', 'm', 'a', 'n'],
['middernag', 'die oggend', 'die middag', 'die aand', 'die nag'],
],
[
['mn', 'o', 'm', 'a', 'n'],
['middernag', 'oggend', 'middag', 'aand', 'nag'],
],
['00:00', ['05:00', '12:00'], ['12:00', '18:00'], ['18:00', '24:00'], ['00:00', '05:00']]
];

View File

@ -0,0 +1,12 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [];

View File

@ -0,0 +1,12 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [];

View File

@ -0,0 +1,25 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['እኩለ ሌሊት', 'ቀ', 'ጥዋት1', 'ከሰዓት1', 'ማታ1', 'ሌሊት1'],
['እኩለ ሌሊት', 'ቀትር', 'ጥዋት1', 'ከሰዓት1', 'ማታ1', 'ሌሊት1'],
],
[
['እኩለ ሌሊት', 'ቀትር', 'ጥዋት', 'ከሰዓት በኋላ', 'ማታ', 'ሌሊት'],
['እኩለ ሌሊት', 'ቀትር', 'ጥዋት1', 'ከሰዓት በኋላ', 'ማታ', 'ሌሊት'],
],
[
'00:00', '12:00', ['06:00', '12:00'], ['12:00', '18:00'], ['18:00', '24:00'],
['00:00', '06:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

View File

@ -0,0 +1,27 @@
/**
* @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
*/
// THIS CODE IS GENERATED - DO NOT MODIFY
// See angular/tools/gulp-tasks/cldr/extract.js
export default [
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ل'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'ص', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً'],
['فجرًا', 'صباحًا', 'ظهرًا', 'بعد الظهر', 'مساءً', 'منتصف الليل', 'ليلاً']
],
[
['03:00', '06:00'], ['06:00', '12:00'], ['12:00', '13:00'], ['13:00', '18:00'],
['18:00', '24:00'], ['00:00', '01:00'], ['01:00', '03:00']
]
];

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