feat(core): support TypeScript 4.3 ()

Switches the repository to TypeScript 4.3 and the latest
version of tslib. This involves updating the peer dependency
ranges on `typescript` for the compiler CLI and for the Bazel
package. Tests for new TypeScript features have been added to
ensure compatibility with Angular's ngtsc compiler.

PR Close 
This commit is contained in:
Paul Gschwendtner 2021-05-06 16:52:39 +02:00 committed by Jessica Janiuk
parent 69296254da
commit 25f763cff8
65 changed files with 384 additions and 148 deletions
aio
aio-builds-setup/dockerbuild/scripts-js
package.jsonyarn.lock
integration
package.json
packages
tools/ts-api-guardian
yarn.lock

@ -33,7 +33,7 @@
"shelljs": "^0.8.4",
"source-map-support": "^0.5.19",
"tar-stream": "^2.1.3",
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"devDependencies": {
"@types/body-parser": "^1.19.0",
@ -49,6 +49,6 @@
"supertest": "^4.0.2",
"tslint": "^6.1.3",
"tslint-jasmine-noSkipOrFocus": "^1.0.9",
"typescript": "^4.2.4"
"typescript": "^4.3.2"
}
}

@ -2505,10 +2505,10 @@ tslib@^1.8.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
tslib@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
tslib@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
tslint-jasmine-noSkipOrFocus@^1.0.9:
version "1.0.9"
@ -2563,10 +2563,10 @@ typedarray-to-buffer@^3.1.5:
dependencies:
is-typedarray "^1.0.0"
typescript@^4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==
typescript@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==
undefsafe@^2.0.2:
version "2.0.2"

@ -99,7 +99,7 @@
"@angular/service-worker": "12.0.2",
"@webcomponents/custom-elements": "1.4.3",
"rxjs": "^6.6.7",
"tslib": "^2.1.0",
"tslib": "^2.2.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
@ -168,7 +168,7 @@
"tree-kill": "^1.1.0",
"ts-node": "^10.0.0",
"tslint": "~6.1.3",
"typescript": "~4.2.4",
"typescript": "~4.3.2",
"uglify-js": "^3.13.3",
"unist-util-filter": "^2.0.3",
"unist-util-source": "^3.0.0",

@ -12244,7 +12244,7 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@4.2.4, typescript@~4.2.4:
typescript@4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==
@ -12254,6 +12254,11 @@ typescript@~3.2.2:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d"
integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==
typescript@~4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==
ua-parser-js@^0.7.23:
version "0.7.28"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31"

@ -100,6 +100,12 @@ INTEGRATION_TESTS = {
# root @npm//typescript package.
"pinned_npm_packages": ["typescript"],
},
"typings_test_ts43": {
# Special case for `typings_test_ts43` test as we want to pin
# `typescript` at version 4.3.x for that test and not link to the
# root @npm//typescript package.
"pinned_npm_packages": ["typescript"],
},
}
[

@ -0,0 +1,69 @@
/**
* @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
*/
import * as animations from '@angular/animations';
import * as animationsBrowser from '@angular/animations/browser';
import * as animationsBrowserTesting from '@angular/animations/browser/testing';
import * as common from '@angular/common';
import * as commonHttp from '@angular/common/http';
import * as commonTesting from '@angular/common/testing';
import * as commonHttpTesting from '@angular/common/testing';
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 elements from '@angular/elements';
import * as forms from '@angular/forms';
import * as platformBrowser from '@angular/platform-browser';
import * as platformBrowserDynamic from '@angular/platform-browser-dynamic';
import * as platformBrowserDynamicTesting from '@angular/platform-browser-dynamic/testing';
import * as platformBrowserAnimations from '@angular/platform-browser/animations';
import * as platformBrowserTesting from '@angular/platform-browser/testing';
import * as platformServer from '@angular/platform-server';
import * as platformServerInit from '@angular/platform-server/init';
import * as platformServerTesting from '@angular/platform-server/testing';
import * as router from '@angular/router';
import * as routerTesting from '@angular/router/testing';
import * as routerUpgrade from '@angular/router/upgrade';
import * as serviceWorker from '@angular/service-worker';
import * as upgrade from '@angular/upgrade';
import * as upgradeStatic from '@angular/upgrade/static';
import * as upgradeTesting from '@angular/upgrade/static/testing';
export default {
animations,
animationsBrowser,
animationsBrowserTesting,
common,
commonTesting,
commonHttp,
commonHttpTesting,
compiler,
compilerTesting,
core,
coreTesting,
elements,
forms,
platformBrowser,
platformBrowserTesting,
platformBrowserDynamic,
platformBrowserDynamicTesting,
platformBrowserAnimations,
platformServer,
platformServerInit,
platformServerTesting,
router,
routerTesting,
routerUpgrade,
serviceWorker,
upgrade,
upgradeStatic,
upgradeTesting,
};

@ -0,0 +1,28 @@
{
"name": "angular-integration",
"description": "Assert that users with TypeScript 4.3 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/elements": "file:../../dist/packages-dist/elements",
"@angular/forms": "file:../../dist/packages-dist/forms",
"@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/service-worker": "file:../../dist/packages-dist/service-worker",
"@angular/upgrade": "file:../../dist/packages-dist/upgrade",
"@types/jasmine": "file:../../node_modules/@types/jasmine",
"rxjs": "file:../../node_modules/rxjs",
"typescript": "4.3.2",
"zone.js": "file:../../dist/zone.js-dist/archive/zone.js.tgz"
},
"scripts": {
"test": "tsc"
}
}

@ -0,0 +1,26 @@
{
"compilerOptions": {
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"outDir": "./dist/out-tsc",
"rootDir": ".",
"target": "es5",
"lib": [
"es5",
"dom",
"es2015.collection",
"es2015.iterable",
"es2015.promise"
],
"types": [],
},
"files": [
"include-all.ts",
"node_modules/@types/jasmine/index.d.ts"
]
}

@ -151,9 +151,9 @@
"terser": "^4.4.0",
"tmp": "0.2.1",
"tsickle": "0.38.1",
"tslib": "^2.1.0",
"tslib": "^2.2.0",
"tslint": "6.1.3",
"typescript": "~4.2.4",
"typescript": "~4.3.2",
"xhr2": "0.2.1",
"yaml": "^1.10.0",
"yargs": "^17.0.0"

@ -8,7 +8,7 @@
"node": "^12.14.1 || >=14.0.0"
},
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER"

@ -26,13 +26,13 @@
"@microsoft/api-extractor": "7.7.11",
"shelljs": "0.8.4",
"tsickle": "^0.38.0",
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"peerDependencies": {
"@angular/compiler-cli": "0.0.0-PLACEHOLDER",
"@bazel/typescript": ">=1.0.0",
"terser": "^4.3.1",
"typescript": ">=4.2.3 <4.3",
"typescript": ">=4.2.3 <4.4",
"rollup": ">=1.20.0",
"rollup-plugin-commonjs": ">=9.0.0",
"rollup-plugin-node-resolve": ">=4.2.0",

@ -9,7 +9,7 @@
},
"locales": "locales",
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER",

@ -11,6 +11,7 @@ import * as ts from 'typescript';
import {absoluteFromSourceFile} from '../../../src/ngtsc/file_system';
import {Logger} from '../../../src/ngtsc/logging';
import {ClassDeclaration, ClassMember, ClassMemberKind, CtorParameter, Declaration, DeclarationNode, Decorator, EnumMember, Import, isConcreteDeclaration, isDecoratorIdentifier, isNamedClassDeclaration, isNamedFunctionDeclaration, isNamedVariableDeclaration, KnownDeclaration, reflectObjectLiteral, SpecialDeclarationKind, TypeScriptReflectionHost, TypeValueReference, TypeValueReferenceKind, ValueUnavailableKind} from '../../../src/ngtsc/reflection';
import {isSymbolWithValueDeclaration, SymbolWithValueDeclaration} from '../../../src/ngtsc/util/src/typescript';
import {isWithinPackage} from '../analysis/util';
import {BundleProgram} from '../packages/bundle_program';
import {findAll, getNameText, hasNameIdentifier, isDefined, stripDollarSuffix} from '../utils';
@ -213,7 +214,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
// That didn't work so now try getting it from the "inner" declaration.
const classSymbol = this.getClassSymbol(clazz);
if (classSymbol === undefined ||
if (classSymbol?.implementation.valueDeclaration === undefined ||
!isNamedDeclaration(classSymbol.implementation.valueDeclaration)) {
return null;
}
@ -241,7 +242,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
}
private getNameFromClassSymbolDeclaration(
classSymbol: NgccClassSymbol, declaration: ts.Declaration): ts.Identifier {
classSymbol: NgccClassSymbol, declaration: ts.Declaration|undefined): ts.Identifier {
if (declaration === undefined) {
throw new Error(
`getInternalNameOfClass() called on a class with an undefined internal declaration. External class name: ${
@ -721,12 +722,12 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
return undefined;
}
let implementationSymbol = declarationSymbol;
let implementationSymbol: ts.Symbol|undefined = declarationSymbol;
if (innerDeclaration !== null && isNamedDeclaration(innerDeclaration)) {
implementationSymbol = this.checker.getSymbolAtLocation(innerDeclaration.name) as ClassSymbol;
implementationSymbol = this.checker.getSymbolAtLocation(innerDeclaration.name);
}
if (implementationSymbol === undefined) {
if (!isSymbolWithValueDeclaration(implementationSymbol)) {
return undefined;
}
@ -740,8 +741,9 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
return classSymbol;
}
private getAdjacentSymbol(declarationSymbol: ClassSymbol, implementationSymbol: ClassSymbol):
ClassSymbol|undefined {
private getAdjacentSymbol(
declarationSymbol: ClassSymbol,
implementationSymbol: SymbolWithValueDeclaration): SymbolWithValueDeclaration|undefined {
if (declarationSymbol === implementationSymbol) {
return undefined;
}
@ -755,9 +757,9 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
if (adjacentDeclaration === undefined || !isNamedVariableDeclaration(adjacentDeclaration)) {
return undefined;
}
const adjacentSymbol =
this.checker.getSymbolAtLocation(adjacentDeclaration.name) as ClassSymbol;
if (adjacentSymbol === declarationSymbol || adjacentSymbol === implementationSymbol) {
const adjacentSymbol = this.checker.getSymbolAtLocation(adjacentDeclaration.name);
if (adjacentSymbol === declarationSymbol || adjacentSymbol === implementationSymbol ||
!isSymbolWithValueDeclaration(adjacentSymbol)) {
return undefined;
}
return adjacentSymbol;

@ -292,7 +292,7 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost {
const members: ClassMember[] = [];
if (propertyDefinition.setter) {
members.push({
node,
node: node!,
implementation: propertyDefinition.setter,
kind: ClassMemberKind.Setter,
type: null,
@ -310,7 +310,7 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost {
}
if (propertyDefinition.getter) {
members.push({
node,
node: node!,
implementation: propertyDefinition.getter,
kind: ClassMemberKind.Getter,
type: null,

@ -8,6 +8,7 @@
import * as ts from 'typescript';
import {ClassDeclaration, Declaration, Decorator, ReflectionHost} from '../../../src/ngtsc/reflection';
import {SymbolWithValueDeclaration} from '../../../src/ngtsc/util/src/typescript';
export const PRE_R3_MARKER = '__PRE_R3__';
export const POST_R3_MARKER = '__POST_R3__';
@ -47,13 +48,13 @@ export interface NgccClassSymbol {
* inner declaration does not need to satisfy the requirements imposed on a publicly visible class
* declaration.
*/
implementation: ts.Symbol;
implementation: SymbolWithValueDeclaration;
/**
* Represents the symbol corresponding to a variable within a class IIFE that may be used to
* attach static properties or decorated.
*/
adjacent?: ts.Symbol;
adjacent?: SymbolWithValueDeclaration;
}
/**

@ -421,7 +421,7 @@ export class UmdReflectionHost extends Esm5ReflectionHost {
const exportsSymbol = this.checker.getSymbolsInScope(id, ts.SymbolFlags.Variable)
.find(symbol => symbol.name === 'exports');
const node = exportsSymbol !== undefined &&
const node = exportsSymbol?.valueDeclaration !== undefined &&
!ts.isFunctionExpression(exportsSymbol.valueDeclaration.parent) ?
// There is a locally defined `exports` variable that is not a function parameter.
// So this `exports` identifier must be a local variable and does not represent the module.

@ -7,7 +7,7 @@
*/
import {DepGraph} from 'dependency-graph';
import {DtsProcessing, PartiallyOrderedTasks, Task} from '../../src/execution/tasks/api';
import {EntryPoint} from '../../src/packages/entry_point';
import {EntryPoint, EntryPointJsonProperty} from '../../src/packages/entry_point';
/**
* Create a set of tasks and a graph of their interdependencies.
@ -53,7 +53,13 @@ export function createTasksAndGraph(
for (let tIdx = 0; tIdx < tasksPerEntryPointCount; tIdx++) {
const processDts = tIdx === 0 ? DtsProcessing.Yes : DtsProcessing.No;
tasks.push({entryPoint, formatProperty: `prop-${tIdx}`, processDts} as Task);
const formatProperty = `prop-${tIdx}` as EntryPointJsonProperty;
tasks.push({
entryPoint,
formatProperty: formatProperty,
formatPropertiesToMarkAsProcessed: [],
processDts
});
}
}

@ -33,7 +33,12 @@ describe('SerialTaskQueue', () => {
const entryPoint = {name: `entry-point-${i}`, path: `/path/to/entry/point/${i}`} as
EntryPoint;
const processDts = i % 2 === 0 ? DtsProcessing.Yes : DtsProcessing.No;
tasks.push({entryPoint: entryPoint, formatProperty: `prop-${i}`, processDts} as Task);
tasks.push({
entryPoint: entryPoint,
formatProperty: `prop-${i}`,
formatPropertiesToMarkAsProcessed: [],
processDts
} as Task);
graph.addNode(entryPoint.path);
}
const dependencies = computeTaskDependencies(tasks, graph);

@ -23,12 +23,12 @@
"semver": "^7.0.0",
"source-map": "^0.6.1",
"sourcemap-codec": "^1.4.8",
"tslib": "^2.1.0",
"tslib": "^2.2.0",
"yargs": "^17.0.0"
},
"peerDependencies": {
"@angular/compiler": "0.0.0-PLACEHOLDER",
"typescript": ">=4.2.3 <4.3"
"typescript": ">=4.2.3 <4.4"
},
"repository": {
"type": "git",

@ -51,6 +51,10 @@ export function findExportedNameOfNode(
* `ts.ExportSpecifier`s and need to be unwrapped.
*/
function symbolDeclaresNode(sym: ts.Symbol, node: ts.Node, checker: ts.TypeChecker): boolean {
if (sym.declarations === undefined) {
return false;
}
return sym.declarations.some(decl => {
if (ts.isExportSpecifier(decl)) {
const exportedSymbol = checker.getExportSpecifierLocalTargetSymbol(decl);

@ -277,7 +277,7 @@ export class TypeScriptReflectionHost implements ReflectionHost {
return null;
}
const namespaceSymbol = this.checker.getSymbolAtLocation(namespaceIdentifier);
if (!namespaceSymbol) {
if (!namespaceSymbol || namespaceSymbol.declarations === undefined) {
return null;
}
const declaration =

@ -150,9 +150,12 @@ export class MetadataDtsModuleScopeResolver implements DtsModuleScopeResolver {
return dirOrPipe;
}
// TypeScript incorrectly narrows the type here:
// https://github.com/microsoft/TypeScript/issues/43966.
// TODO: Remove/Update once https://github.com/microsoft/TypeScript/issues/43966 is resolved.
return {
...dirOrPipe,
ref: ref.cloneWithAlias(alias),
};
} as T;
}
}

@ -13,6 +13,7 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/imports",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/util",
"@npm//typescript",
],
)

@ -8,6 +8,7 @@
import * as ts from 'typescript';
import {ClassDeclaration} from '../../reflection';
import {SymbolWithValueDeclaration} from '../../util/src/typescript';
/**
* Metadata on a directive which is available in the scope of a template.
@ -16,7 +17,7 @@ export interface DirectiveInScope {
/**
* The `ts.Symbol` for the directive class.
*/
tsSymbol: ts.Symbol;
tsSymbol: SymbolWithValueDeclaration;
/**
* The module which declares the directive.

@ -10,7 +10,8 @@ import {TmplAstElement, TmplAstReference, TmplAstTemplate, TmplAstVariable} from
import * as ts from 'typescript';
import {AbsoluteFsPath} from '../../file_system';
import {ClassDeclaration} from '../../reflection';
import {SymbolWithValueDeclaration} from '../../util/src/typescript';
import {DirectiveInScope} from './scope';
export enum SymbolKind {
@ -303,8 +304,8 @@ export interface ClassSymbol {
tsType: ts.Type;
/** The `ts.Symbol` for class. */
tsSymbol: ts.Symbol;
tsSymbol: SymbolWithValueDeclaration;
/** The position for the variable declaration for the class instance. */
shimLocation: ShimLocation;
}
}

@ -17,7 +17,7 @@ import {ProgramDriver, UpdateMode} from '../../program_driver';
import {ClassDeclaration, isNamedClassDeclaration, ReflectionHost} from '../../reflection';
import {ComponentScopeReader, TypeCheckScopeRegistry} from '../../scope';
import {isShim} from '../../shims';
import {getSourceFileOrNull} from '../../util/src/typescript';
import {getSourceFileOrNull, isSymbolWithValueDeclaration} from '../../util/src/typescript';
import {DirectiveInScope, ElementSymbol, FullTemplateMapping, GlobalCompletion, OptimizeFor, PipeInScope, ProgramTypeCheckAdapter, ShimLocation, Symbol, TemplateId, TemplateSymbol, TemplateTypeChecker, TypeCheckableDirectiveMeta, TypeCheckingConfig} from '../api';
import {TemplateDiagnostic} from '../diagnostics';
@ -577,7 +577,7 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker {
continue;
}
const tsSymbol = typeChecker.getSymbolAtLocation(dir.ref.node.name);
if (tsSymbol === undefined) {
if (!isSymbolWithValueDeclaration(tsSymbol)) {
continue;
}

@ -12,7 +12,7 @@ import * as ts from 'typescript';
import {AbsoluteFsPath} from '../../file_system';
import {ClassDeclaration} from '../../reflection';
import {ComponentScopeReader} from '../../scope';
import {isAssignment} from '../../util/src/typescript';
import {isAssignment, isSymbolWithValueDeclaration} from '../../util/src/typescript';
import {BindingSymbol, DirectiveSymbol, DomBindingSymbol, ElementSymbol, ExpressionSymbol, InputBindingSymbol, OutputBindingSymbol, PipeSymbol, ReferenceSymbol, ShimLocation, Symbol, SymbolKind, TemplateSymbol, TsNodeSymbolInfo, TypeCheckableDirectiveMeta, VariableSymbol} from '../api';
import {ExpressionIdentifier, findAllMatchingNodes, findFirstMatchingNode, hasExpressionIdentifier} from './comments';
@ -119,8 +119,7 @@ export class SymbolBuilder {
return nodes
.map(node => {
const symbol = this.getSymbolOfTsNode(node.parent);
if (symbol === null || symbol.tsSymbol === null ||
symbol.tsSymbol.valueDeclaration === undefined ||
if (symbol === null || !isSymbolWithValueDeclaration(symbol.tsSymbol) ||
!ts.isClassDeclaration(symbol.tsSymbol.valueDeclaration)) {
return null;
}
@ -314,7 +313,8 @@ export class SymbolBuilder {
// In either case, `_t1["index"]` or `_t1.index`, `node.expression` is _t1.
// The retrieved symbol for _t1 will be the variable declaration.
const tsSymbol = this.getTypeChecker().getSymbolAtLocation(node.expression);
if (tsSymbol === undefined || tsSymbol.declarations.length === 0 || selector === null) {
if (tsSymbol?.declarations === undefined || tsSymbol.declarations.length === 0 ||
selector === null) {
return null;
}
@ -329,8 +329,7 @@ export class SymbolBuilder {
}
const symbol = this.getSymbolOfTsNode(declaration);
if (symbol === null || symbol.tsSymbol === null ||
symbol.tsSymbol.valueDeclaration === undefined ||
if (symbol === null || !isSymbolWithValueDeclaration(symbol.tsSymbol) ||
!ts.isClassDeclaration(symbol.tsSymbol.valueDeclaration)) {
return null;
}
@ -444,7 +443,10 @@ export class SymbolBuilder {
}
const pipeInstance = this.getSymbolOfTsNode(pipeDeclaration.valueDeclaration);
if (pipeInstance === null || pipeInstance.tsSymbol === null) {
// The instance should never be null, nor should the symbol lack a value declaration. This
// is because the node used to look for the `pipeInstance` symbol info is a value
// declaration of another symbol (i.e. the `pipeDeclaration` symbol).
if (pipeInstance === null || !isSymbolWithValueDeclaration(pipeInstance.tsSymbol)) {
return null;
}

@ -74,8 +74,8 @@ runInEachFileSystem(() => {
const {attributes} = getAstElements(templateTypeChecker, cmp)[0];
const symbol = templateTypeChecker.getSymbolOfNode(attributes[0], cmp)!;
assertInputBindingSymbol(symbol);
expect(
(symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration).name.getText())
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('name');
// Ensure we can go back to the original location using the shim location
@ -91,8 +91,8 @@ runInEachFileSystem(() => {
const {attributes} = getAstElements(templateTypeChecker, cmp)[0];
const symbol = templateTypeChecker.getSymbolOfNode(attributes[0], cmp)!;
assertInputBindingSymbol(symbol);
expect(
(symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration).name.getText())
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('name');
});
});
@ -303,7 +303,7 @@ runInEachFileSystem(() => {
function expectUserSymbol(userSymbol: Symbol) {
assertVariableSymbol(userSymbol);
expect(userSymbol.tsSymbol!.escapedName).toContain('$implicit');
expect(userSymbol.tsSymbol!.declarations[0].parent!.getText())
expect(userSymbol.tsSymbol!.declarations![0].parent!.getText())
.toContain('NgForOfContext');
expect(program.getTypeChecker().typeToString(userSymbol.tsType!)).toEqual('User');
expect((userSymbol).declaration).toEqual(templateNode.variables[0]);
@ -312,7 +312,7 @@ runInEachFileSystem(() => {
function expectIndexSymbol(indexSymbol: Symbol) {
assertVariableSymbol(indexSymbol);
expect(indexSymbol.tsSymbol!.escapedName).toContain('index');
expect(indexSymbol.tsSymbol!.declarations[0].parent!.getText())
expect(indexSymbol.tsSymbol!.declarations![0].parent!.getText())
.toContain('NgForOfContext');
expect(program.getTypeChecker().typeToString(indexSymbol.tsType!)).toEqual('number');
expect((indexSymbol).declaration).toEqual(templateNode.variables[1]);
@ -370,7 +370,7 @@ runInEachFileSystem(() => {
const symbol = templateTypeChecker.getSymbolOfNode(inputNode, cmp)!;
assertExpressionSymbol(symbol);
expect(program.getTypeChecker().symbolToString(symbol.tsSymbol!)).toEqual('street');
expect((symbol.tsSymbol!.declarations[0] as ts.PropertyDeclaration).parent.name!.getText())
expect((symbol.tsSymbol!.declarations![0] as ts.PropertyDeclaration).parent.name!.getText())
.toEqual('Address');
expect(program.getTypeChecker().typeToString(symbol.tsType)).toEqual('string');
@ -427,7 +427,7 @@ runInEachFileSystem(() => {
assertExpressionSymbol(propReadSymbol);
expect(program.getTypeChecker().symbolToString(propReadSymbol.tsSymbol!))
.toEqual('street');
expect((propReadSymbol.tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((propReadSymbol.tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.parent.name!.getText())
.toEqual('Address');
expect(program.getTypeChecker().typeToString(propReadSymbol.tsType))
@ -441,7 +441,7 @@ runInEachFileSystem(() => {
assertExpressionSymbol(methodCallSymbol);
expect(program.getTypeChecker().symbolToString(methodCallSymbol.tsSymbol!))
.toEqual('speak');
expect((methodCallSymbol.tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((methodCallSymbol.tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.parent.name!.getText())
.toEqual('Person');
expect(program.getTypeChecker().typeToString(methodCallSymbol.tsType))
@ -856,7 +856,7 @@ runInEachFileSystem(() => {
const inputAbinding = (nodes[0] as TmplAstElement).inputs[0];
const aSymbol = templateTypeChecker.getSymbolOfNode(inputAbinding, cmp)!;
assertInputBindingSymbol(aSymbol);
expect((aSymbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((aSymbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('inputA');
});
@ -892,14 +892,14 @@ runInEachFileSystem(() => {
const inputAbinding = (nodes[0] as TmplAstElement).inputs[0];
const aSymbol = templateTypeChecker.getSymbolOfNode(inputAbinding, cmp)!;
assertInputBindingSymbol(aSymbol);
expect((aSymbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((aSymbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('inputA');
const inputBbinding = (nodes[0] as TmplAstElement).inputs[1];
const bSymbol = templateTypeChecker.getSymbolOfNode(inputBbinding, cmp)!;
assertInputBindingSymbol(bSymbol);
expect((bSymbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((bSymbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('inputB');
});
@ -953,8 +953,8 @@ runInEachFileSystem(() => {
TmplAstBoundAttribute;
const symbol = templateTypeChecker.getSymbolOfNode(ngForOfBinding, cmp)!;
assertInputBindingSymbol(symbol);
expect(
(symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration).name.getText())
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('ngForOf');
});
@ -1050,10 +1050,10 @@ runInEachFileSystem(() => {
const inputAbinding = (nodes[0] as TmplAstElement).inputs[0];
const symbol = templateTypeChecker.getSymbolOfNode(inputAbinding, cmp)!;
assertInputBindingSymbol(symbol);
expect(
(symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration).name.getText())
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('inputA');
expect((symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.parent.name?.text)
.toEqual('TestDir');
});
@ -1091,10 +1091,10 @@ runInEachFileSystem(() => {
const inputAbinding = (nodes[0] as TmplAstElement).inputs[0];
const symbol = templateTypeChecker.getSymbolOfNode(inputAbinding, cmp)!;
assertInputBindingSymbol(symbol);
expect(
(symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration).name.getText())
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('otherInputA');
expect((symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.parent.name?.text)
.toEqual('TestDir');
});
@ -1142,10 +1142,11 @@ runInEachFileSystem(() => {
const symbol = templateTypeChecker.getSymbolOfNode(inputAbinding, cmp)!;
assertInputBindingSymbol(symbol);
expect(new Set(symbol.bindings.map(
b => (b.tsSymbol!.declarations[0] as ts.PropertyDeclaration).name.getText())))
b => (b.tsSymbol!.declarations![0] as ts.PropertyDeclaration).name.getText())))
.toEqual(new Set(['inputA', 'otherDirInputA']));
expect(new Set(symbol.bindings.map(
b => (b.tsSymbol!.declarations[0] as ts.PropertyDeclaration).parent.name?.text)))
expect(
new Set(symbol.bindings.map(
b => (b.tsSymbol!.declarations![0] as ts.PropertyDeclaration).parent.name?.text)))
.toEqual(new Set(['TestDir', 'OtherDir']));
});
});
@ -1186,14 +1187,14 @@ runInEachFileSystem(() => {
const outputABinding = (nodes[0] as TmplAstElement).outputs[0];
const aSymbol = templateTypeChecker.getSymbolOfNode(outputABinding, cmp)!;
assertOutputBindingSymbol(aSymbol);
expect((aSymbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((aSymbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('outputA');
const outputBBinding = (nodes[0] as TmplAstElement).outputs[1];
const bSymbol = templateTypeChecker.getSymbolOfNode(outputBBinding, cmp)!;
assertOutputBindingSymbol(bSymbol);
expect((bSymbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((bSymbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('outputB');
});
@ -1239,10 +1240,10 @@ runInEachFileSystem(() => {
const outputABinding = (nodes[0] as TmplAstElement).outputs[0];
const symbol = templateTypeChecker.getSymbolOfNode(outputABinding, cmp)!;
assertOutputBindingSymbol(symbol);
expect(
(symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration).name.getText())
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('outputA');
expect((symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.parent.name?.text)
.toEqual('TestDir');
});
@ -1304,10 +1305,10 @@ runInEachFileSystem(() => {
const outputABinding = (nodes[0] as TmplAstElement).outputs[0];
const symbol = templateTypeChecker.getSymbolOfNode(outputABinding, cmp)!;
assertOutputBindingSymbol(symbol);
expect(
(symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration).name.getText())
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('outputA');
expect((symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.parent.name?.text)
.toEqual('TestDir');
});
@ -1353,10 +1354,10 @@ runInEachFileSystem(() => {
const outputABinding = (nodes[0] as TmplAstElement).outputs[0];
const symbol = templateTypeChecker.getSymbolOfNode(outputABinding, cmp)!;
assertOutputBindingSymbol(symbol);
expect(
(symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration).name.getText())
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.name.getText())
.toEqual('ngModelChange');
expect((symbol.bindings[0].tsSymbol!.declarations[0] as ts.PropertyDeclaration)
expect((symbol.bindings[0].tsSymbol!.declarations![0] as ts.PropertyDeclaration)
.parent.name?.text)
.toEqual('TestDir');
});

@ -13,6 +13,23 @@ import * as ts from 'typescript';
import {AbsoluteFsPath, getFileSystem} from '../../file_system';
import {DeclarationNode} from '../../reflection';
/**
* Type describing a symbol that is guaranteed to have a value declaration.
*/
export type SymbolWithValueDeclaration = ts.Symbol&{
valueDeclaration: ts.Declaration;
declarations: ts.Declaration[];
};
export function isSymbolWithValueDeclaration(symbol: ts.Symbol|null|
undefined): symbol is SymbolWithValueDeclaration {
// If there is a value declaration set, then the `declarations` property is never undefined. We
// still check for the property to exist as this matches with the type that `symbol` is narrowed
// to.
return symbol != null && symbol.valueDeclaration !== undefined &&
symbol.declarations !== undefined;
}
export function isDtsPath(filePath: string): boolean {
return D_TS.test(filePath);
}

@ -25,7 +25,7 @@ const MIN_TS_VERSION = '4.2.3';
* Note: this check is disabled in g3, search for
* `angularCompilerOptions.disableTypeScriptVersionCheck` config param value in g3.
*/
const MAX_TS_VERSION = '4.3.0';
const MAX_TS_VERSION = '4.4.0';
/**
* The currently used version of TypeScript, which can be adjusted for testing purposes using

@ -308,6 +308,36 @@ export declare class AnimationEvent {
expect(diags.length).toBe(0);
});
// https://devblogs.microsoft.com/typescript/announcing-typescript-4-3-beta/#separate-write-types-on-properties
it('should support separate write types on inputs', () => {
env.tsconfig({strictTemplates: true});
env.write('test.ts', `
import {Component, NgModule, Input} from '@angular/core';
@Component({
selector: 'test',
template: '<target-cmp disabled></target-cmp>',
})
export class TestCmp {}
@Component({template: '', selector: 'target-cmp'})
export class TargetCmp {
@Input()
get disabled(): boolean { return this._disabled; }
set disabled(value: string|boolean) { this._disabled = value === '' || !!value; }
private _disabled = false;
}
@NgModule({
declarations: [TestCmp, TargetCmp],
})
export class Module {}
`);
const diags = env.driveDiagnostics();
console.error(diags);
expect(diags.length).toBe(0);
});
describe('strictInputTypes', () => {
beforeEach(() => {
env.write('test.ts', `

@ -8,7 +8,7 @@
"node": "^12.14.1 || >=14.0.0"
},
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"repository": {
"type": "git",

@ -8,7 +8,7 @@
"node": "^12.14.1 || >=14.0.0"
},
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"peerDependencies": {
"rxjs": "^6.5.3",

@ -70,7 +70,8 @@ export class InitialNavigationCollector {
return null;
}
if (symbolForIdentifier.declarations.length === 0) {
if (symbolForIdentifier.declarations === undefined ||
symbolForIdentifier.declarations.length === 0) {
return null;
}

@ -52,7 +52,8 @@ export class RelativeLinkResolutionCollector {
return null;
}
if (symbolForIdentifier.declarations.length === 0) {
if (symbolForIdentifier.declarations === undefined ||
symbolForIdentifier.declarations.length === 0) {
return null;
}

@ -152,7 +152,7 @@ export class DeclarationUsageVisitor {
node: ts.PropertyAccessExpression, checkSetter: boolean, checkGetter: boolean) {
const propertySymbol = this._getPropertyAccessSymbol(node);
if (!propertySymbol || !propertySymbol.declarations.length ||
if (propertySymbol?.declarations === undefined || propertySymbol.declarations.length === 0 ||
(propertySymbol.getFlags() & ts.SymbolFlags.Accessor) === 0) {
return;
}

@ -19,7 +19,7 @@ export function getImportOfIdentifier(typeChecker: ts.TypeChecker, node: ts.Iden
null {
const symbol = typeChecker.getSymbolAtLocation(node);
if (!symbol || !symbol.declarations.length) {
if (!symbol || symbol.declarations === undefined || !symbol.declarations.length) {
return null;
}

@ -65,7 +65,7 @@ export function makeDecorator<T>(
// prevents the property is copied during subclassing.
const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
(cls as any)[ANNOTATIONS] :
Object.defineProperty(cls, ANNOTATIONS, {value: []})[ANNOTATIONS];
(Object.defineProperty(cls, ANNOTATIONS, {value: []}) as any)[ANNOTATIONS];
annotations.push(annotationInstance);

@ -233,6 +233,8 @@ export function getParentRenderElement(view: ViewData, renderHost: any, def: Nod
(renderParent.element!.componentRendererType!.encapsulation ===
ViewEncapsulation.ShadowDom ||
// TODO(FW-2290): remove the `encapsulation === 1` fallback logic in v12.
// @ts-ignore TODO: Remove as part of FW-2290. TS complains about us dealing with an enum
// value that is not known (but previously was the value for ViewEncapsulation.Native)
renderParent.element!.componentRendererType!.encapsulation === 1))) {
// only children of non components, or children of components with native encapsulation should
// be attached.

@ -64,7 +64,7 @@ describe('InjectorDef-based createInjector()', () => {
providedIn: null,
// ChildService is derived from ServiceWithDep, so the factory function here must do the right
// thing and create an instance of the requested type if one is given.
factory: (t?: typeof ServiceWithDep) => new(t || ServiceWithDep)(ɵɵinject(Service)),
factory: (t?: any) => new(t || ServiceWithDep)(ɵɵinject(Service)),
});
}

@ -8,7 +8,7 @@
"node": "^12.14.1 || >=14.0.0"
},
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER",

@ -8,7 +8,7 @@
"node": "^12.14.1 || >=14.0.0"
},
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER",

@ -430,7 +430,7 @@ describe('Validators', () => {
const v = Validators.composeAsync(
[promiseValidator({'one': true}), promiseValidator({'two': true})])!;
let errorMap: {[key: string]: any}|null = undefined!;
let errorMap: {[key: string]: any}|null = null;
(v(new FormControl('invalid')) as Observable<ValidationErrors|null>)
.pipe(first())
.subscribe((errors: {[key: string]: any}|null) => errorMap = errors);
@ -444,7 +444,7 @@ describe('Validators', () => {
[new AsyncValidatorDirective('expected', {'one': true})]);
const validatorFn = Validators.composeAsync(normalizedValidators)!;
let errorMap: {[key: string]: any}|null = undefined!;
let errorMap: {[key: string]: any}|null = null;
(validatorFn(new FormControl('invalid')) as Observable<ValidationErrors|null>)
.pipe(first())
.subscribe((errors: {[key: string]: any}|null) => errorMap = errors);
@ -468,7 +468,7 @@ describe('Validators', () => {
it('should ignore nulls', fakeAsync(() => {
const v = Validators.composeAsync([promiseValidator({'one': true}), null!])!;
let errorMap: {[key: string]: any}|null = undefined!;
let errorMap: {[key: string]: any}|null = null;
(v(new FormControl('invalid')) as Observable<ValidationErrors|null>)
.pipe(first())
.subscribe((errors: {[key: string]: any}|null) => errorMap = errors);
@ -494,7 +494,7 @@ describe('Validators', () => {
const v = Validators.composeAsync(
[observableValidator({'one': true}), observableValidator({'two': true})])!;
let errorMap: {[key: string]: any}|null = undefined!;
let errorMap: {[key: string]: any}|null = null;
(v(new FormControl('invalid')) as Observable<ValidationErrors|null>)
.pipe(first())
.subscribe((errors: {[key: string]: any}|null) => errorMap = errors);
@ -507,7 +507,7 @@ describe('Validators', () => {
[new AsyncValidatorDirective('expected', {'one': true})]);
const validatorFn = Validators.composeAsync(normalizedValidators)!;
let errorMap: {[key: string]: any}|null = undefined!;
let errorMap: {[key: string]: any}|null = null;
(validatorFn(new FormControl('invalid')) as Observable<ValidationErrors|null>)
.pipe(first())
.subscribe((errors: {[key: string]: any}|null) => errorMap = errors)!;
@ -529,7 +529,7 @@ describe('Validators', () => {
it('should ignore nulls', () => {
const v = Validators.composeAsync([observableValidator({'one': true}), null!])!;
let errorMap: {[key: string]: any}|null = undefined!;
let errorMap: {[key: string]: any}|null = null;
(v(new FormControl('invalid')) as Observable<ValidationErrors|null>)
.pipe(first())
.subscribe((errors: {[key: string]: any}|null) => errorMap = errors);
@ -547,7 +547,7 @@ describe('Validators', () => {
const v = Validators.composeAsync(
[getTimerObs(100, {one: true}), getTimerObs(200, {two: true})])!;
let errorMap: {[key: string]: any}|null = undefined!;
let errorMap: {[key: string]: any}|null|undefined = undefined;
(v(new FormControl('invalid')) as Observable<ValidationErrors|null>)
.pipe(first())
.subscribe((errors: {[key: string]: any}|null) => errorMap = errors);

@ -82,9 +82,11 @@ export class CompletionBuilder<N extends TmplAstNode|AST> {
*/
getCompletionEntryDetails(
entryName: string, formatOptions: ts.FormatCodeOptions|ts.FormatCodeSettings|undefined,
preferences: ts.UserPreferences|undefined): ts.CompletionEntryDetails|undefined {
preferences: ts.UserPreferences|undefined,
data: ts.CompletionEntryData|undefined): ts.CompletionEntryDetails|undefined {
if (this.isPropertyExpressionCompletion()) {
return this.getPropertyExpressionCompletionDetails(entryName, formatOptions, preferences);
return this.getPropertyExpressionCompletionDetails(
entryName, formatOptions, preferences, data);
} else if (this.isElementTagCompletion()) {
return this.getElementTagCompletionDetails(entryName);
} else if (this.isElementAttributeCompletion()) {
@ -167,12 +169,13 @@ export class CompletionBuilder<N extends TmplAstNode|AST> {
private getPropertyExpressionCompletionDetails(
this: PropertyExpressionCompletionBuilder, entryName: string,
formatOptions: ts.FormatCodeOptions|ts.FormatCodeSettings|undefined,
preferences: ts.UserPreferences|undefined): ts.CompletionEntryDetails|undefined {
preferences: ts.UserPreferences|undefined,
data: ts.CompletionEntryData|undefined): ts.CompletionEntryDetails|undefined {
let details: ts.CompletionEntryDetails|undefined = undefined;
if (this.node instanceof EmptyExpr || this.node instanceof BoundEvent ||
this.node.receiver instanceof ImplicitReceiver) {
details =
this.getGlobalPropertyExpressionCompletionDetails(entryName, formatOptions, preferences);
details = this.getGlobalPropertyExpressionCompletionDetails(
entryName, formatOptions, preferences, data);
} else {
const location = this.compiler.getTemplateTypeChecker().getExpressionCompletionLocation(
this.node, this.component);
@ -181,7 +184,7 @@ export class CompletionBuilder<N extends TmplAstNode|AST> {
}
details = this.tsLS.getCompletionEntryDetails(
location.shimPath, location.positionInShimFile, entryName, formatOptions,
/* source */ undefined, preferences);
/* source */ undefined, preferences, data);
}
if (details !== undefined) {
details.displayParts = filterAliasImports(details.displayParts);
@ -292,7 +295,8 @@ export class CompletionBuilder<N extends TmplAstNode|AST> {
private getGlobalPropertyExpressionCompletionDetails(
this: PropertyExpressionCompletionBuilder, entryName: string,
formatOptions: ts.FormatCodeOptions|ts.FormatCodeSettings|undefined,
preferences: ts.UserPreferences|undefined): ts.CompletionEntryDetails|undefined {
preferences: ts.UserPreferences|undefined,
data: ts.CompletionEntryData|undefined): ts.CompletionEntryDetails|undefined {
const completions =
this.templateTypeChecker.getGlobalCompletions(this.template, this.component, this.node);
if (completions === null) {
@ -323,7 +327,7 @@ export class CompletionBuilder<N extends TmplAstNode|AST> {
} else {
return this.tsLS.getCompletionEntryDetails(
componentContext.shimPath, componentContext.positionInShimFile, entryName, formatOptions,
/* source */ undefined, preferences);
/* source */ undefined, preferences, data);
}
}

@ -244,7 +244,8 @@ export class LanguageService {
getCompletionEntryDetails(
fileName: string, position: number, entryName: string,
formatOptions: ts.FormatCodeOptions|ts.FormatCodeSettings|undefined,
preferences: ts.UserPreferences|undefined): ts.CompletionEntryDetails|undefined {
preferences: ts.UserPreferences|undefined,
data: ts.CompletionEntryData|undefined): ts.CompletionEntryDetails|undefined {
return this.withCompilerAndPerfTracing(PerfPhase.LsCompletions, (compiler) => {
if (!isTemplateContext(compiler.getCurrentProgram(), fileName, position)) {
return undefined;
@ -254,7 +255,7 @@ export class LanguageService {
if (builder === null) {
return undefined;
}
return builder.getCompletionEntryDetails(entryName, formatOptions, preferences);
return builder.getCompletionEntryDetails(entryName, formatOptions, preferences, data);
});
}

@ -70,9 +70,10 @@ export class OpenBuffer {
getCompletionEntryDetails(
entryName: string, formatOptions?: ts.FormatCodeOptions|ts.FormatCodeSettings,
preferences?: ts.UserPreferences): ts.CompletionEntryDetails|undefined {
preferences?: ts.UserPreferences, data?: ts.CompletionEntryData): ts.CompletionEntryDetails
|undefined {
return this.ngLS.getCompletionEntryDetails(
this.scriptInfo.fileName, this._cursor, entryName, formatOptions, preferences);
this.scriptInfo.fileName, this._cursor, entryName, formatOptions, preferences, data);
}
getTcb() {
@ -118,4 +119,4 @@ function extractCursorInfo(textWithCursor: string): {cursor: number, text: strin
cursor,
text: textWithCursor.substr(0, cursor) + textWithCursor.substr(cursor + 1),
};
}
}

@ -95,15 +95,17 @@ export function create(info: ts.server.PluginCreateInfo): NgLanguageService {
function getCompletionEntryDetails(
fileName: string, position: number, entryName: string,
formatOptions: ts.FormatCodeOptions|ts.FormatCodeSettings|undefined, source: string|undefined,
preferences: ts.UserPreferences|undefined): ts.CompletionEntryDetails|undefined {
preferences: ts.UserPreferences|undefined,
data: ts.CompletionEntryData|undefined): ts.CompletionEntryDetails|undefined {
if (angularOnly) {
return ngLS.getCompletionEntryDetails(
fileName, position, entryName, formatOptions, preferences);
fileName, position, entryName, formatOptions, preferences, data);
} else {
// If TS could answer the query, then return that result. Otherwise, return from Angular LS.
return tsLS.getCompletionEntryDetails(
fileName, position, entryName, formatOptions, source, preferences) ??
ngLS.getCompletionEntryDetails(fileName, position, entryName, formatOptions, preferences);
fileName, position, entryName, formatOptions, source, preferences, data) ??
ngLS.getCompletionEntryDetails(
fileName, position, entryName, formatOptions, preferences, data);
}
}

@ -88,7 +88,7 @@ export function collectMemberMethods(
const members: ts.MethodDeclaration[] = [];
const apparentProps = typeChecker.getTypeAtLocation(clazz).getApparentProperties();
for (const prop of apparentProps) {
if (ts.isMethodDeclaration(prop.valueDeclaration) && prop.valueDeclaration) {
if (prop.valueDeclaration && ts.isMethodDeclaration(prop.valueDeclaration)) {
members.push(prop.valueDeclaration);
}
}

@ -242,6 +242,9 @@ function selectSignature(type: ts.Type, context: TypeContext, types: Symbol[]):
function allParameterTypesMatch(signature: ts.Signature) {
const tc = context.checker;
return signature.getParameters().every((parameter: ts.Symbol, i: number) => {
if (parameter.valueDeclaration === undefined) {
return false;
}
const type = tc.getTypeOfSymbolAtLocation(parameter, parameter.valueDeclaration);
return type === passedInTypes[i];
});

@ -59,8 +59,8 @@ describe('reflector_host_spec', () => {
// This resolves all Angular directives in the project.
ngLSHost.getAnalyzedModules();
const secondCount = spy.calls.count();
expect(secondCount).toBeGreaterThan(500);
expect(secondCount).toBeLessThan(600);
expect(secondCount).toBeGreaterThan(400);
expect(secondCount).toBeLessThan(500);
spy.calls.reset();
// Third count is due to recompution after the program changes.

@ -10,7 +10,7 @@
"rxjs": "^6.5.3"
},
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"repository": {
"type": "git",

@ -8,7 +8,7 @@
"node": "^12.14.1 || >=14.0.0"
},
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER",

@ -8,7 +8,7 @@
"node": "^12.14.1 || >=14.0.0"
},
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"peerDependencies": {
"@angular/animations": "0.0.0-PLACEHOLDER",

@ -102,10 +102,15 @@ export class DomRendererFactory2 implements RendererFactory2 {
(<EmulatedEncapsulationDomRenderer2>renderer).applyToHost(element);
return renderer;
}
// @ts-ignore TODO: Remove as part of FW-2290. TS complains about us dealing with an enum
// value that is not known (but previously was the value for ViewEncapsulation.Native)
case 1:
case ViewEncapsulation.ShadowDom:
// TODO(FW-2290): remove the `case 1:` fallback logic and the warning in v12.
if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
// @ts-ignore TODO: Remove as part of FW-2290. TS complains about us dealing with an
// enum value that is not known (but previously was the value for
// ViewEncapsulation.Native)
!hasLoggedNativeEncapsulationWarning && type.encapsulation === 1) {
hasLoggedNativeEncapsulationWarning = true;
console.warn(

@ -17,7 +17,7 @@
},
"dependencies": {
"domino": "^2.1.2",
"tslib": "^2.1.0",
"tslib": "^2.2.0",
"xhr2": "^0.2.0"
},
"repository": {

@ -21,7 +21,7 @@
},
"homepage": "https://github.com/angular/angular/tree/master/packages/router",
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER",

@ -8,7 +8,7 @@
"node": "^12.14.1 || >=14.0.0"
},
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER",

@ -8,7 +8,7 @@
"node": "^12.14.1 || >=14.0.0"
},
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER",

@ -28,8 +28,11 @@ if (typeof window !== 'undefined') {
passiveSupported = true;
}
});
window.addEventListener('test', options, options);
window.removeEventListener('test', options, options);
// Note: We pass the `options` object as the event handler too. This is not compatible with the
// signature of `addEventListener` or `removeEventListener` but enables us to remove the handler
// without an actual handler.
window.addEventListener('test', options as any, options);
window.removeEventListener('test', options as any, options);
} catch (err) {
passiveSupported = false;
}

@ -163,9 +163,9 @@ Zone.__load_patch('jasmine', (global: any, Zone: ZoneType, api: _ZonePrivate) =>
let spyObj: any;
if (propertyNames) {
const defineProperty = Object.defineProperty;
Object.defineProperty = function(obj: any, p: string, attributes: any) {
Object.defineProperty = function<T>(obj: T, p: PropertyKey, attributes: any) {
return defineProperty.call(
this, obj, p, {...attributes, configurable: true, enumerable: true});
this, obj, p, {...attributes, configurable: true, enumerable: true}) as T;
};
try {
spyObj = originalCreateSpyObj.apply(this, args);

@ -8,7 +8,7 @@
"fesm2015": "./fesm2015/zone.js",
"typings": "./zone.d.ts",
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.2.0"
},
"devDependencies": {
"@externs/nodejs": "^1.5.0",
@ -19,7 +19,7 @@
"mocha": "^8.0.0",
"mock-require": "3.0.3",
"promises-aplus-tests": "^2.1.2",
"typescript": "4.2.4"
"typescript": "4.3.2"
},
"scripts": {
"closuretest": "./scripts/closure/closure_compiler.sh",

@ -14,6 +14,6 @@
"zone.js": "file:../../../../dist/bin/packages/zone.js/npm_package"
},
"devDependencies": {
"typescript": "~4.2.4"
"typescript": "~4.3.2"
}
}

@ -3884,7 +3884,7 @@ tr46@^2.0.2:
dependencies:
punycode "^2.1.1"
tslib@^2.1.0:
tslib@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
@ -3923,10 +3923,10 @@ typedarray-to-buffer@^3.1.5:
dependencies:
is-typedarray "^1.0.0"
typescript@4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==
typescript@4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==
unbox-primitive@^1.0.1:
version "1.0.1"

@ -25,7 +25,7 @@
"@types/node": "^10.9.4",
"jasmine": "^3.1.0",
"source-map-support": "^0.5.9",
"typescript": "4.2.4"
"typescript": "4.3.2"
},
"keywords": [
"typescript"

@ -13330,7 +13330,7 @@ tslib@1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
integrity sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==
tslib@2.2.0, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.2.0:
tslib@2.2.0, tslib@^2.0.1, tslib@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
@ -13491,7 +13491,7 @@ typescript@3.2.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d"
integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==
typescript@4.2.4, typescript@~4.2.4:
typescript@4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==
@ -13506,6 +13506,11 @@ typescript@~3.7.2:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.7.tgz#c931733e2ec10dda56b855b379cc488a72a81199"
integrity sha512-MmQdgo/XenfZPvVLtKZOq9jQQvzaUAUpcKW8Z43x9B2fOm4S5g//tPtMweZUIP+SoBqrVPEIm+dJeQ9dfO0QdA==
typescript@~4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==
uglify-js@^3.1.4:
version "3.13.8"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.8.tgz#7c2f9f2553f611f3ff592bdc19c6fb208dc60afb"