Skip to content

build: update to typescript v3.8 #18789

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,23 @@ jobs:
# Run project tests with NGC and View Engine.
- run: bazel test src/... --build_tag_filters=-docs-package,-e2e --test_tag_filters=-e2e --config=view-engine --build_tests_only

# ----------------------------------------------------------------------------
# Job that runs all Bazel integration tests.
# ----------------------------------------------------------------------------
integration_tests:
<<: *job_defaults
resource_class: xlarge
environment:
GCP_DECRYPT_TOKEN: *gcp_decrypt_token
steps:
- *checkout_code
- *restore_cache
- *setup_bazel_ci_config
- *setup_bazel_remote_execution
- *setup_bazel_binary
# Integration tests run with --config=view-engine because we release with View Engine.
- run: bazel test integration/... --build_tests_only --config=view-engine

# ----------------------------------------------------------------------------
# Job that runs all Bazel tests against material-components-web@canary
# ----------------------------------------------------------------------------
Expand Down Expand Up @@ -525,6 +542,8 @@ workflows:
filters: *ignore_presubmit_branch_filter
- api_golden_checks:
filters: *ignore_presubmit_branch_filter
- integration_tests:
filters: *ignore_presubmit_branch_filter
- tests_local_browsers:
filters: *ignore_presubmit_branch_filter
- tests_browserstack:
Expand Down
5 changes: 4 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,12 @@
# Universal app
/src/universal-app/** @jelbourn

# Integration tests
/integration/** @jelbourn @devversion

# Tooling
/.circleci/** @angular/dev-infra-components
/.yarn/** @angular/dev-infra-components
/.yarn/** @angular/dev-infra-components
/scripts/** @angular/dev-infra-components
/test/** @angular/dev-infra-components
/tools/** @angular/dev-infra-components
Expand Down
46 changes: 46 additions & 0 deletions integration/ts-compat/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package(default_visibility = ["//visibility:public"])

load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test")
load("//integration/ts-compat:import-all-entry-points.bzl", "generate_import_all_entry_points_file")

write_file(
name = "import-all-entry-points-file",
out = "import-all-entry-points.ts",
content = [generate_import_all_entry_points_file()],
)

# List of TypeScript packages that we want to run the compatibility test against.
# The list contains NPM module names that resolve to the desired TypeScript version.
typescript_version_packages = [
"typescript-3.6",
"typescript-3.7",
"typescript",
]

# Generates a NodeJS test for each configured TypeScript version.
[
nodejs_test(
name = ts_pkg_name,
args = [ts_pkg_name],
data = [
"helpers.js",
"test.js",
":import-all-entry-points-file",
"//src/cdk:npm_package",
"//src/cdk-experimental:npm_package",
"//src/google-maps:npm_package",
"//src/material:npm_package",
"//src/material-experimental:npm_package",
"//src/youtube-player:npm_package",
"@npm//shelljs",
"@npm//%s" % ts_pkg_name,
"@npm//@types/node",
],
entry_point = "test.js",
tags = [
"integration",
],
)
for ts_pkg_name in typescript_version_packages
]
85 changes: 85 additions & 0 deletions integration/ts-compat/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
const {relative, sep, join} = require('path');
const {readdirSync, readFileSync, existsSync} = require('fs');
const {set, ln, rm, mkdir} = require('shelljs');
const {fork} = require('child_process');
const runfiles = require(process.env.BAZEL_NODE_RUNFILES_HELPER);

// Exit if any command fails.
set('-e');

// List of NPM packages that have been built for the current test target.
const npmPackages = getNpmPackagesFromRunfiles();
// Path to the node modules of the workspace.
const nodeModulesDir = runfiles.resolve('npm/node_modules');
// Path to the generated file that imports all entry-points.
const testFilePath = require.resolve('./import-all-entry-points.ts');

/**
* Runs the TypeScript compatibility test with the specified tsc binary. The
* compatibility test, links the built release packages into `node_modules` and
* compiles a test file using the specified tsc binary which imports all entry-points.
*/
exports.runTypeScriptCompatibilityTest = async (tscBinPath) => {
return new Promise((resolve, reject) => {
const angularDir = join(nodeModulesDir, '@angular/');

// Create the `node_modules/@angular` directory in case it's not present.
mkdir('-p', angularDir);

// Symlink npm packages into `node_modules/` so that the project can
// be compiled without path mappings (simulating a real project).
for (const {name, pkgPath} of npmPackages) {
console.info(`Linking "@angular/${name}" into node modules..`);
ln('-s', pkgPath, join(angularDir, name));
}

const tscArgs = [
'--strict',
'--lib', 'es2015,dom',
// Ensures that `node_modules` can be resolved. By default, in sandbox environments the
// node modules cannot be resolved because they are wrapped in the `npm/node_modules` folder
'--baseUrl', nodeModulesDir,
testFilePath
];
// Run `tsc` to compile the project. The stdout/stderr output is inherited, so that
// warnings and errors are printed to the console.
const tscProcess = fork(tscBinPath, tscArgs, {stdio: 'inherit'});

tscProcess.on('exit', (exitCode) => {
// Remove symlinks to keep a clean repository state.
for (const {name} of npmPackages) {
console.info(`Removing link for "@angular/${name}"..`);
rm(join(angularDir, name));
}
exitCode === 0 ? resolve() : reject();
});
});
};

/**
* Gets all built Angular NPM package artifacts by querying the Bazel runfiles.
* In case there is a runfiles manifest (e.g. on Windows), the packages are resolved
* through the manifest because the runfiles are not symlinked and cannot be searched
* within the real filesystem. TODO: Remove if Bazel on Windows uses runfile symlinking.
*/
function getNpmPackagesFromRunfiles() {
// Path to the Bazel runfiles manifest if present. This file is present if runfiles are
// not symlinked into the runfiles directory.
const runfilesManifestPath = process.env.RUNFILES_MANIFEST_FILE;
const workspacePath = 'angular_material/src';
if (!runfilesManifestPath) {
const packageRunfilesDir = join(process.env.RUNFILES, workspacePath);
return readdirSync(packageRunfilesDir)
.map(name => ({name, pkgPath: join(packageRunfilesDir, name, 'npm_package/')}))
.filter(({pkgPath}) => existsSync(pkgPath));
}
const workspaceManifestPathRegex = new RegExp(`^${workspacePath}/[\\w-]+/npm_package$`);
return readFileSync(runfilesManifestPath, 'utf8')
.split('\n')
.map(mapping => mapping.split(' '))
.filter(([runfilePath]) => runfilePath.match(workspaceManifestPathRegex))
.map(([runfilePath, realPath]) => ({
name: relative(workspacePath, runfilePath).split(sep)[0],
pkgPath: realPath,
}));
}
44 changes: 44 additions & 0 deletions integration/ts-compat/import-all-entry-points.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
load("//src/cdk:config.bzl", "CDK_ENTRYPOINTS")
load("//src/cdk-experimental:config.bzl", "CDK_EXPERIMENTAL_ENTRYPOINTS")
load("//src/material:config.bzl", "MATERIAL_ENTRYPOINTS", "MATERIAL_TESTING_ENTRYPOINTS")
load("//src/material-experimental:config.bzl", "MATERIAL_EXPERIMENTAL_ENTRYPOINTS", "MATERIAL_EXPERIMENTAL_TESTING_ENTRYPOINTS")

"""Converts the given string to an identifier."""

def convert_to_identifier(name):
return name.replace("/", "_").replace("-", "_")

"""Creates imports and exports for the given entry-point and package."""

def create_import_export(entry_point, pkg_name):
identifier = "%s_%s" % (convert_to_identifier(pkg_name), convert_to_identifier(entry_point))
return """
import * as {0} from "@angular/{1}/{2}";
export {{ {0} }};
""".format(identifier, pkg_name, entry_point)

"""
Creates a file that imports all entry-points as namespace. The namespaces will be
re-exported. This ensures that all entry-points can successfully compile.
"""

def generate_import_all_entry_points_file():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way we could consolidate on a single, canonical list of packages for the repo? Right now I think there's a handful of places that need to be updated when we add a new package. Either that, or just documenting all the places that need to be updated

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯 Definitely agreed. I've been trying to reduce this type of duplication (as seen with entry-points in the system config etc.).

I'll work on a follow-up that gives us a better list of release packages. The problem always comes from the fact that we can't easily access these variables outside of Bazel (e.g. in the release scripts).

output = """
import * as cdk from "@angular/cdk";
import * as cdk_experimental from "@angular/cdk-experimental";
// Note: The primary entry-point for Angular Material does not have
// any exports, so it cannot be imported as module.
import * as material_experimental from "@angular/material-experimental";
import * as google_maps from "@angular/google-maps";
import * as youtube_player from "@angular/youtube-player";
export {cdk, cdk_experimental, material_experimental, google_maps, youtube_player};
"""
for ep in CDK_ENTRYPOINTS:
output += create_import_export(ep, "cdk")
for ep in CDK_EXPERIMENTAL_ENTRYPOINTS:
output += create_import_export(ep, "cdk-experimental")
for ep in MATERIAL_ENTRYPOINTS + MATERIAL_TESTING_ENTRYPOINTS:
output += create_import_export(ep, "material")
for ep in MATERIAL_EXPERIMENTAL_ENTRYPOINTS + MATERIAL_EXPERIMENTAL_TESTING_ENTRYPOINTS:
output += create_import_export(ep, "material-experimental")
return output
19 changes: 19 additions & 0 deletions integration/ts-compat/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Test script that runs the TypeScript compatibility tests against a specified
* TypeScript package that is passed through command line. The script is executed
* by a Bazel `nodejs_test` target and relies on Bazel runfile resolution.
*/

const {runTypeScriptCompatibilityTest} = require('./helpers');

if (module === require.main) {
const [pkgName] = process.argv.slice(2);
if (!pkgName) {
console.error('No TypeScript package specified. Exiting..');
process.exit(1);
}
runTypeScriptCompatibilityTest(require.resolve(`${pkgName}/bin/tsc`)).catch(e => {
console.error(e);
process.exit(1);
});
}
34 changes: 18 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@
},
"version": "9.1.2",
"dependencies": {
"@angular/animations": "^9.0.5",
"@angular/common": "^9.0.5",
"@angular/compiler": "^9.0.5",
"@angular/core": "^9.0.5",
"@angular/elements": "^9.0.5",
"@angular/forms": "^9.0.5",
"@angular/platform-browser": "^9.0.5",
"@angular/animations": "^9.1.0-next.4",
"@angular/common": "^9.1.0-next.4",
"@angular/compiler": "^9.1.0-next.4",
"@angular/core": "^9.1.0-next.4",
"@angular/elements": "^9.1.0-next.4",
"@angular/forms": "^9.1.0-next.4",
"@angular/platform-browser": "^9.1.0-next.4",
"@types/googlemaps": "^3.37.0",
"@types/youtube": "^0.0.38",
"@webcomponents/custom-elements": "^1.1.0",
Expand All @@ -65,11 +65,11 @@
"devDependencies": {
"@angular-devkit/core": "^9.0.4",
"@angular-devkit/schematics": "^9.0.4",
"@angular/bazel": "^9.0.5",
"@angular/compiler-cli": "^9.0.5",
"@angular/platform-browser-dynamic": "^9.0.5",
"@angular/platform-server": "^9.0.5",
"@angular/router": "^9.0.5",
"@angular/bazel": "^9.1.0-next.4",
"@angular/compiler-cli": "^9.1.0-next.4",
"@angular/platform-browser-dynamic": "^9.1.0-next.4",
"@angular/platform-server": "^9.1.0-next.4",
"@angular/router": "^9.1.0-next.4",
"@bazel/bazelisk": "^1.3.0",
"@bazel/buildifier": "^0.29.0",
"@bazel/ibazel": "0.12.0",
Expand Down Expand Up @@ -133,7 +133,7 @@
"moment": "^2.18.1",
"node-fetch": "^2.6.0",
"parse5": "^5.0.0",
"protractor": "^5.4.2",
"protractor": "^5.4.3",
"requirejs": "^2.3.6",
"rollup": "~1.25.0",
"rollup-plugin-alias": "^1.4.0",
Expand All @@ -151,14 +151,16 @@
"terser": "^4.3.9",
"ts-api-guardian": "^0.5.0",
"ts-node": "^3.0.4",
"tsickle": "0.38.0",
"tsickle": "0.38.1",
"tslint": "^6.0.0",
"tsutils": "^3.0.0",
"typescript": "~3.7.4",
"typescript": "~3.8.3",
"typescript-3.6": "npm:typescript@~3.6.4",
"typescript-3.7": "npm:typescript@~3.7.0",
"vrsource-tslint-rules": "5.1.1"
},
"resolutions": {
"dgeni-packages/typescript": "3.7.4",
"dgeni-packages/typescript": "3.8.3",
"**/graceful-fs": "4.2.2"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import {getVersionUpgradeData, RuleUpgradeData} from '../upgrade-data';
* Rule that walks through every identifier that is part of Angular Material or thr CDK
* and replaces the outdated name with the new one if specified in the upgrade data.
*/
// TODO: rework this rule to identify symbols using the import identifier resolver. This
// makes it more robust, less AST convoluted and is more TypeScript AST idiomatic. COMP-300.
export class ClassNamesRule extends MigrationRule<RuleUpgradeData> {
/** Change data that upgrades to the specified target version. */
data: ClassNameUpgradeData[] = getVersionUpgradeData(this, 'classNames');
Expand Down
3 changes: 2 additions & 1 deletion src/cdk/schematics/utils/ast/ng-module-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export function hasNgModuleImport(tree: Tree, modulePath: string, className: str
function resolveIdentifierOfExpression(expression: ts.Expression): ts.Identifier | null {
if (ts.isIdentifier(expression)) {
return expression;
} else if (ts.isPropertyAccessExpression(expression)) {
} else if (ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.name)) {
return expression.name;
}
return null;
Expand Down Expand Up @@ -84,6 +84,7 @@ function isNgModuleCallExpression(callExpression: ts.CallExpression): boolean {
return false;
}

// The `NgModule` call expression name is never referring to a `PrivateIdentifier`.
const decoratorIdentifier = resolveIdentifierOfExpression(callExpression.expression);
return decoratorIdentifier ? decoratorIdentifier.text === 'NgModule' : false;
}
Loading