diff --git a/.circleci/config.yml b/.circleci/config.yml
index adc58e6f77cf..a1f2361f654c 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -87,6 +87,7 @@ var_12: &ignore_presubmit_branch_filter
branches:
ignore:
- "_presubmit"
+ - "ivy-2019"
# -----------------------------
# Container version of CircleCI
@@ -348,7 +349,8 @@ workflows:
release_output:
jobs:
- - build_release_packages
+ - build_release_packages:
+ filters: *ignore_presubmit_branch_filter
- build_devapp_aot:
filters: *ignore_presubmit_branch_filter
requires:
diff --git a/.gitignore b/.gitignore
index 85f4a9059549..75e800a17e5e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,4 +40,4 @@ yarn-error.log
testem.log
/.chrome
/.git
-/.firebase
\ No newline at end of file
+/.firebase
diff --git a/package.json b/package.json
index 5405e93fcb23..304b29efc2bc 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,7 @@
"systemjs": "0.19.43",
"tsickle": "^0.34.0",
"tslib": "^1.9.3",
- "zone.js": "^0.8.26"
+ "zone.js": "^0.8.29"
},
"devDependencies": {
"@angular-devkit/core": "^7.1.2",
@@ -55,6 +55,7 @@
"@angular/platform-browser-dynamic": "^7.1.3",
"@angular/platform-server": "^7.1.3",
"@angular/router": "^7.1.3",
+ "@bazel/bazel": "~0.21.0",
"@bazel/ibazel": "^0.9.0",
"@bazel/karma": "0.22.0",
"@bazel/typescript": "0.22.0",
@@ -111,7 +112,8 @@
"karma-browserstack-launcher": "^1.3.0",
"karma-chrome-launcher": "^2.2.0",
"karma-firefox-launcher": "^1.0.1",
- "karma-jasmine": "^2.0.1",
+ "karma-jasmine": "github:jelbourn/karma-jasmine",
+ "karma-json-result-reporter": "^1.0.0",
"karma-parallel": "^0.3.0",
"karma-sauce-launcher": "^2.0.2",
"karma-sourcemap-loader": "^0.3.7",
@@ -134,7 +136,8 @@
"selenium-webdriver": "^3.6.0",
"sorcery": "^0.10.0",
"source-map-support": "^0.5.9",
- "stylelint": "^9.9.0",
+ "stylelint": "^8.4.0",
+ "systemjs-builder": "^0.16.13",
"ts-node": "^3.0.4",
"tsconfig-paths": "^2.3.0",
"tslint": "^5.12.0",
diff --git a/scripts/ivy/README.md b/scripts/ivy/README.md
new file mode 100644
index 000000000000..50955800d0b3
--- /dev/null
+++ b/scripts/ivy/README.md
@@ -0,0 +1,39 @@
+# Experimental Ivy Scripts
+
+These scripts exist for the testing of Ivy in the Material repo, pre-launch. This is uncharted
+territory, so building Material this way may or may not work, and depending on the output is
+non-trivial.
+
+## Usage
+
+For the first execution, a version of Angular must be built with `ngtsc`. To do this, a current
+Angular repo is passed to `install-angular.sh`.
+
+```bash
+$ ./scripts/ivy/install-angular.sh /path/to/angular
+```
+
+This will replace `node_modules/@angular` with `ngtsc`-built versions of Angular packages.
+
+Once that step is complete, the demo application can be built.
+
+```bash
+# Build the demo-app with Ivy
+$ ./scripts/ivy/build.sh
+# And serve it
+$ cd dist/demo && http-server
+```
+
+## Known issues
+* Much of the compilation will fail without commits in the Angular repo not yet in `master`.
+* Ivy does not support the `ViewContainerRef.createComponent()` API yet, so the demo-app is unable to get past starting the Angular Router.
+
+## Maintaining tsconfig files
+
+The `ivy` branch has a lot of updated tsconfig files. These were mutated via script, which can
+be re-run if needed
+
+```bash
+# Update tsconfigs
+./scripts/ivy/update-tsconfigs.sh
+```
diff --git a/scripts/ivy/build.sh b/scripts/ivy/build.sh
new file mode 100755
index 000000000000..06eacbfa2d82
--- /dev/null
+++ b/scripts/ivy/build.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+set -e
+
+echo ">>> Build Material"
+rm -rf dist
+gulp build:devapp
+
+echo ">>> Rebuild dev-app with ngtsc"
+node_modules/.bin/ngc -p src/dev-app/tsconfig-build.json
+
+echo ">>> Bundle demo-app with SystemJS"
+node ./src/dev-app/systemjs-bundle.js
+
+echo ">>> Assembling app"
+mkdir dist/demo
+cp dist/packages/dev-app/bundle.js dist/demo
+cp src/dev-app/index.html dist/demo
+cp dist/packages/dev-app/theme.css dist/demo
+cp 'node_modules/@webcomponents/custom-elements/custom-elements.min.js' dist/demo
+cp node_modules/core-js/client/core.js dist/demo
+cp node_modules/systemjs/dist/system.src.js dist/demo
+cp node_modules/zone.js/dist/zone.js dist/demo
+cp node_modules/hammerjs/hammer.min.js dist/demo
+
+echo ">>> Done."
+echo "Output: $(pwd)/dist/demo"
\ No newline at end of file
diff --git a/scripts/ivy/fix-tsconfig.js b/scripts/ivy/fix-tsconfig.js
new file mode 100755
index 000000000000..876491ee4958
--- /dev/null
+++ b/scripts/ivy/fix-tsconfig.js
@@ -0,0 +1,59 @@
+#!/usr/bin/env node
+
+/**
+ * @license
+ * Copyright Google LLC 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 script updates a tsconfig-build.json file for Ivy compilation. It has 3 main goals:
+ *
+ * 1. Change "public-api.ts" to "index.ts" in the files array.
+ * 2. Add "enableIvy": "ngtsc" to "angularCompilerOptions".
+ * 3. Turn "annotateForClosureCompiler" off (so decorators will tree-shake properly).
+ */
+
+const fs = require('fs');
+
+function replacePublicApiTs(file) {
+ if (file === 'public-api.ts') {
+ return 'index.ts';
+ } else {
+ return file;
+ }
+}
+
+
+// Read in the tsconfig json file.
+let source = fs.readFileSync(process.argv[2], 'utf8')
+ .split(/\n/)
+ .filter(line => !line.trim().startsWith('/') && !line.trim().startsWith('*'))
+ .join('\n')
+ .replace(/,(\s+)]/g, '$1]')
+ .replace(/,(\s+)}/g, '$1}');
+
+let json = null;
+try {
+ json = JSON.parse(source);
+} catch (e) {
+ console.error(`Error parsing tsconfig ${process.argv[2]}:`);
+ console.error(source);
+ console.error(`Error was:`, e);
+ process.exit(1);
+}
+
+if (json['files'] && Array.isArray(json['files'])) {
+ json['files'] = json['files'].map(replacePublicApiTs);
+}
+
+if (json['angularCompilerOptions']) {
+ if (json['angularCompilerOptions']['annotateForClosureCompiler']) {
+ delete json['angularCompilerOptions']['annotateForClosureCompiler']
+ }
+ json['angularCompilerOptions']['enableIvy'] = 'ngtsc';
+}
+
+fs.writeFileSync(process.argv[2], JSON.stringify(json, null, 2));
diff --git a/scripts/ivy/generate-blocklist.js b/scripts/ivy/generate-blocklist.js
new file mode 100755
index 000000000000..f162b2c8de57
--- /dev/null
+++ b/scripts/ivy/generate-blocklist.js
@@ -0,0 +1,98 @@
+#!/usr/bin/env node
+
+const path = require('path');
+const fs = require('fs');
+
+const karmaOutput = JSON.parse(fs.readFileSync('/tmp/karma-result.json'));
+
+
+let generatedBlocklist = {};
+for (const desc of Object.keys(karmaOutput)) {
+ // If karma encounters global errors, it adds them to an array keyed __BROWSER_ERRORS__.
+ // We ignore this since it's not associated with any particular test. It generally shouldn't
+ // happen at all because we're using a forked version of karma-jasmine that does not report
+ // global errors per-suite.
+ if (desc === '__BROWSER_ERRORS__') {
+ continue;
+ }
+
+ generatedBlocklist = {...generatedBlocklist, ...getFullFailure(karmaOutput[desc], desc)};
+}
+
+// We want to "remember" the notes from the current blocklist on angular/angular unless the
+// error message has changed. We need to know where the local angular/angular repo is.
+const angularRepoPath = process.argv[2];
+if (!angularRepoPath) {
+ console.error('Please provide the path to your local angular/angular repo as the first argument');
+ process.exit(1);
+}
+
+// Read the contents of the previous blocklist.
+const previousBlocklistPath =
+ path.join(angularRepoPath, 'tools', 'material-ci', 'angular_material_test_blocklist.js');
+const previousBlocklistContent = fs.readFileSync(previousBlocklistPath, 'utf-8');
+
+// Because the blocklist is a javascript file meant to be executed, we just actually execute it with
+// eval. Create a dummy `window` for it to add to.
+const window = {};
+eval(previousBlocklistContent);
+const previousBlocklist = window.testBlocklist;
+
+// Copy any existing test notes.
+for (const testName of Object.keys(generatedBlocklist)) {
+ if (previousBlocklist[testName] &&
+ generatedBlocklist[testName].error === previousBlocklist[testName].error) {
+ generatedBlocklist[testName].notes = previousBlocklist[testName].notes;
+ }
+}
+
+// Format the output as an executable javascript program.
+const output =
+`/**
+ * @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
+ */
+
+/**
+ * Blocklist of unit tests from angular/material2 with ivy that are skipped when running on
+ * angular/angular. As bugs are resolved, items should be removed from this blocklist.
+ *
+ * The \`notes\` section should be used to keep track of specific issues associated with the failures.
+ */
+
+// clang-format off
+// tslint:disable
+
+window.testBlocklist = ${JSON.stringify(generatedBlocklist, null, 2)};
+// clang-format on`;
+
+// Write that sucker to dist.
+fs.writeFileSync('dist/angular_material_test_blocklist.js', output, 'utf-8');
+
+
+/**
+ * Given a karma test result, get a blocklist entry in the form
+ * {[full test name]: {error: '...', notes: '...'}}
+ */
+function getFullFailure(result, fullName = '') {
+ if (result['log']) {
+ if (result['log'].length) {
+ return {[fullName]: {
+ error: result['log'][0].split('\n')[0],
+ notes: 'Unknown',
+ }};
+ }
+
+ return {};
+ }
+
+ let failures = {};
+ for (const key of Object.keys(result)) {
+ failures = {...failures, ...getFullFailure(result[key], fullName + ' ' + key)};
+ }
+
+ return failures;
+}
diff --git a/scripts/ivy/install-angular.sh b/scripts/ivy/install-angular.sh
new file mode 100755
index 000000000000..f8e7eadeac91
--- /dev/null
+++ b/scripts/ivy/install-angular.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+set -e
+
+
+function clear_existing_angular_install() {
+ echo ">>> clearing existing @angular packages in node_modules"
+ chmod -R u+w node_modules/@angular
+ rm -rf node_modules/@angular/*
+}
+
+function build_angular_packages() {
+ angular_repo_dir=$1
+ echo ">>> Building @angular packages (from ${angular_repo_dir})"
+ pushd ${angular_repo_dir}
+ yarn bazel build --config=release --define=compile=aot //packages/{animations,common,compiler,compiler-cli,core,elements,forms,platform-browser,platform-browser-dynamic,router,upgrade}:npm_package
+ output_path=$(yarn --silent bazel info bazel-bin 2>/dev/null)/packages
+ popd
+}
+
+function install_angular_package() {
+ name=$1
+ echo " @angular/$name"
+ cp -r "${output_path}/${name}/npm_package" "node_modules/@angular/${name}"
+}
+
+
+if [[ "$1" != "" ]]
+then
+ clear_existing_angular_install
+ build_angular_packages $1
+
+ echo ">>> Installing @angular packages"
+ install_angular_package "animations"
+ install_angular_package "common"
+ install_angular_package "compiler"
+ install_angular_package "compiler-cli"
+ install_angular_package "core"
+ install_angular_package "elements"
+ install_angular_package "forms"
+ install_angular_package "platform-browser"
+ install_angular_package "platform-browser-dynamic"
+ install_angular_package "router"
+ install_angular_package "upgrade"
+
+ chmod -R u+w node_modules/@angular
+else
+ echo "Usage: $0 /path/to/angular/repo"
+fi
diff --git a/scripts/ivy/update-tsconfigs.sh b/scripts/ivy/update-tsconfigs.sh
new file mode 100755
index 000000000000..1e524a90dfda
--- /dev/null
+++ b/scripts/ivy/update-tsconfigs.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -e
+
+find src | grep /tsconfig.*json | grep -v '/tsconfig.json' | while read tsconfig; do
+ dir=`dirname $tsconfig`
+ echo "Updating $tsconfig"
+
+ # If no index.ts exists, rename public-api.ts.
+ if [ ! -f $dir/index.ts -a -f $dir/public-api.ts ]
+ then
+ echo "export * from './public_api';" > $dir/index.ts
+ fi
+ node scripts/ivy/fix-tsconfig.js $tsconfig
+done
\ No newline at end of file
diff --git a/src/a11y-demo/menu/menu-a11y.html b/src/a11y-demo/menu/menu-a11y.html
index 0b810c70e2f7..e7c8a592a0e9 100644
--- a/src/a11y-demo/menu/menu-a11y.html
+++ b/src/a11y-demo/menu/menu-a11y.html
@@ -36,11 +36,11 @@
Menu with Icons
Menu with links
-