feat(core): support TypeScript 4.3 (#42022)

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 #42022
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

View File

@ -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"
}
}

View File

@ -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"

View File

@ -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",

View File

@ -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"

View File

@ -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"],
},
}
[

View File

@ -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,
};

View File

@ -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"
}
}

View File

@ -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"
]
}

View File

@ -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"

View File

@ -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"

View File

@ -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",

View File

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

View File

@ -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;

View File

@ -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,

View File

@ -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;
}
/**

View File

@ -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.

View File

@ -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
});
}
}

View File

@ -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);

View File

@ -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",

View File

@ -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);

View File

@ -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 =

View File

@ -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;
}
}

View File

@ -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",
],
)

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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');
});

View File

@ -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);
}

View File

@ -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

View File

@ -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', `

View File

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

View File

@ -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",

View File

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

View File

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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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.

View File

@ -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)),
});
}

View File

@ -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",

View File

@ -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",

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
});
}

View File

@ -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),
};
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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];
});

View File

@ -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.

View File

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

View File

@ -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",

View File

@ -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",

View File

@ -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(

View File

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

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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;
}

View File

@ -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);

View File

@ -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",

View File

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

View File

@ -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"

View File

@ -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"

View File

@ -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"