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", "shelljs": "^0.8.4",
"source-map-support": "^0.5.19", "source-map-support": "^0.5.19",
"tar-stream": "^2.1.3", "tar-stream": "^2.1.3",
"tslib": "^2.1.0" "tslib": "^2.2.0"
}, },
"devDependencies": { "devDependencies": {
"@types/body-parser": "^1.19.0", "@types/body-parser": "^1.19.0",
@ -49,6 +49,6 @@
"supertest": "^4.0.2", "supertest": "^4.0.2",
"tslint": "^6.1.3", "tslint": "^6.1.3",
"tslint-jasmine-noSkipOrFocus": "^1.0.9", "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" version "1.9.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
tslib@^2.1.0: tslib@^2.2.0:
version "2.1.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
tslint-jasmine-noSkipOrFocus@^1.0.9: tslint-jasmine-noSkipOrFocus@^1.0.9:
version "1.0.9" version "1.0.9"
@ -2563,10 +2563,10 @@ typedarray-to-buffer@^3.1.5:
dependencies: dependencies:
is-typedarray "^1.0.0" is-typedarray "^1.0.0"
typescript@^4.2.4: typescript@^4.3.2:
version "4.2.4" version "4.3.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==
undefsafe@^2.0.2: undefsafe@^2.0.2:
version "2.0.2" version "2.0.2"

View File

@ -99,7 +99,7 @@
"@angular/service-worker": "12.0.2", "@angular/service-worker": "12.0.2",
"@webcomponents/custom-elements": "1.4.3", "@webcomponents/custom-elements": "1.4.3",
"rxjs": "^6.6.7", "rxjs": "^6.6.7",
"tslib": "^2.1.0", "tslib": "^2.2.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
}, },
"devDependencies": { "devDependencies": {
@ -168,7 +168,7 @@
"tree-kill": "^1.1.0", "tree-kill": "^1.1.0",
"ts-node": "^10.0.0", "ts-node": "^10.0.0",
"tslint": "~6.1.3", "tslint": "~6.1.3",
"typescript": "~4.2.4", "typescript": "~4.3.2",
"uglify-js": "^3.13.3", "uglify-js": "^3.13.3",
"unist-util-filter": "^2.0.3", "unist-util-filter": "^2.0.3",
"unist-util-source": "^3.0.0", "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" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@4.2.4, typescript@~4.2.4: typescript@4.2.4:
version "4.2.4" version "4.2.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== 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" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d"
integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg== 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: ua-parser-js@^0.7.23:
version "0.7.28" version "0.7.28"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31" 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. # root @npm//typescript package.
"pinned_npm_packages": ["typescript"], "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", "terser": "^4.4.0",
"tmp": "0.2.1", "tmp": "0.2.1",
"tsickle": "0.38.1", "tsickle": "0.38.1",
"tslib": "^2.1.0", "tslib": "^2.2.0",
"tslint": "6.1.3", "tslint": "6.1.3",
"typescript": "~4.2.4", "typescript": "~4.3.2",
"xhr2": "0.2.1", "xhr2": "0.2.1",
"yaml": "^1.10.0", "yaml": "^1.10.0",
"yargs": "^17.0.0" "yargs": "^17.0.0"

View File

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

View File

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

View File

@ -9,7 +9,7 @@
}, },
"locales": "locales", "locales": "locales",
"dependencies": { "dependencies": {
"tslib": "^2.1.0" "tslib": "^2.2.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER", "@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 {absoluteFromSourceFile} from '../../../src/ngtsc/file_system';
import {Logger} from '../../../src/ngtsc/logging'; 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 {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 {isWithinPackage} from '../analysis/util';
import {BundleProgram} from '../packages/bundle_program'; import {BundleProgram} from '../packages/bundle_program';
import {findAll, getNameText, hasNameIdentifier, isDefined, stripDollarSuffix} from '../utils'; 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. // That didn't work so now try getting it from the "inner" declaration.
const classSymbol = this.getClassSymbol(clazz); const classSymbol = this.getClassSymbol(clazz);
if (classSymbol === undefined || if (classSymbol?.implementation.valueDeclaration === undefined ||
!isNamedDeclaration(classSymbol.implementation.valueDeclaration)) { !isNamedDeclaration(classSymbol.implementation.valueDeclaration)) {
return null; return null;
} }
@ -241,7 +242,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
} }
private getNameFromClassSymbolDeclaration( private getNameFromClassSymbolDeclaration(
classSymbol: NgccClassSymbol, declaration: ts.Declaration): ts.Identifier { classSymbol: NgccClassSymbol, declaration: ts.Declaration|undefined): ts.Identifier {
if (declaration === undefined) { if (declaration === undefined) {
throw new Error( throw new Error(
`getInternalNameOfClass() called on a class with an undefined internal declaration. External class name: ${ `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; return undefined;
} }
let implementationSymbol = declarationSymbol; let implementationSymbol: ts.Symbol|undefined = declarationSymbol;
if (innerDeclaration !== null && isNamedDeclaration(innerDeclaration)) { 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; return undefined;
} }
@ -740,8 +741,9 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
return classSymbol; return classSymbol;
} }
private getAdjacentSymbol(declarationSymbol: ClassSymbol, implementationSymbol: ClassSymbol): private getAdjacentSymbol(
ClassSymbol|undefined { declarationSymbol: ClassSymbol,
implementationSymbol: SymbolWithValueDeclaration): SymbolWithValueDeclaration|undefined {
if (declarationSymbol === implementationSymbol) { if (declarationSymbol === implementationSymbol) {
return undefined; return undefined;
} }
@ -755,9 +757,9 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
if (adjacentDeclaration === undefined || !isNamedVariableDeclaration(adjacentDeclaration)) { if (adjacentDeclaration === undefined || !isNamedVariableDeclaration(adjacentDeclaration)) {
return undefined; return undefined;
} }
const adjacentSymbol = const adjacentSymbol = this.checker.getSymbolAtLocation(adjacentDeclaration.name);
this.checker.getSymbolAtLocation(adjacentDeclaration.name) as ClassSymbol; if (adjacentSymbol === declarationSymbol || adjacentSymbol === implementationSymbol ||
if (adjacentSymbol === declarationSymbol || adjacentSymbol === implementationSymbol) { !isSymbolWithValueDeclaration(adjacentSymbol)) {
return undefined; return undefined;
} }
return adjacentSymbol; return adjacentSymbol;

View File

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

View File

@ -8,6 +8,7 @@
import * as ts from 'typescript'; import * as ts from 'typescript';
import {ClassDeclaration, Declaration, Decorator, ReflectionHost} from '../../../src/ngtsc/reflection'; 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 PRE_R3_MARKER = '__PRE_R3__';
export const POST_R3_MARKER = '__POST_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 * inner declaration does not need to satisfy the requirements imposed on a publicly visible class
* declaration. * declaration.
*/ */
implementation: ts.Symbol; implementation: SymbolWithValueDeclaration;
/** /**
* Represents the symbol corresponding to a variable within a class IIFE that may be used to * Represents the symbol corresponding to a variable within a class IIFE that may be used to
* attach static properties or decorated. * 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) const exportsSymbol = this.checker.getSymbolsInScope(id, ts.SymbolFlags.Variable)
.find(symbol => symbol.name === 'exports'); .find(symbol => symbol.name === 'exports');
const node = exportsSymbol !== undefined && const node = exportsSymbol?.valueDeclaration !== undefined &&
!ts.isFunctionExpression(exportsSymbol.valueDeclaration.parent) ? !ts.isFunctionExpression(exportsSymbol.valueDeclaration.parent) ?
// There is a locally defined `exports` variable that is not a function parameter. // 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. // 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 {DepGraph} from 'dependency-graph';
import {DtsProcessing, PartiallyOrderedTasks, Task} from '../../src/execution/tasks/api'; 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. * 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++) { for (let tIdx = 0; tIdx < tasksPerEntryPointCount; tIdx++) {
const processDts = tIdx === 0 ? DtsProcessing.Yes : DtsProcessing.No; 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 const entryPoint = {name: `entry-point-${i}`, path: `/path/to/entry/point/${i}`} as
EntryPoint; EntryPoint;
const processDts = i % 2 === 0 ? DtsProcessing.Yes : DtsProcessing.No; 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); graph.addNode(entryPoint.path);
} }
const dependencies = computeTaskDependencies(tasks, graph); const dependencies = computeTaskDependencies(tasks, graph);

View File

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

View File

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

View File

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

View File

@ -150,9 +150,12 @@ export class MetadataDtsModuleScopeResolver implements DtsModuleScopeResolver {
return dirOrPipe; 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 { return {
...dirOrPipe, ...dirOrPipe,
ref: ref.cloneWithAlias(alias), 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/imports",
"//packages/compiler-cli/src/ngtsc/metadata", "//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/util",
"@npm//typescript", "@npm//typescript",
], ],
) )

View File

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

View File

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

View File

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

View File

@ -12,7 +12,7 @@ import * as ts from 'typescript';
import {AbsoluteFsPath} from '../../file_system'; import {AbsoluteFsPath} from '../../file_system';
import {ClassDeclaration} from '../../reflection'; import {ClassDeclaration} from '../../reflection';
import {ComponentScopeReader} from '../../scope'; 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 {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'; import {ExpressionIdentifier, findAllMatchingNodes, findFirstMatchingNode, hasExpressionIdentifier} from './comments';
@ -119,8 +119,7 @@ export class SymbolBuilder {
return nodes return nodes
.map(node => { .map(node => {
const symbol = this.getSymbolOfTsNode(node.parent); const symbol = this.getSymbolOfTsNode(node.parent);
if (symbol === null || symbol.tsSymbol === null || if (symbol === null || !isSymbolWithValueDeclaration(symbol.tsSymbol) ||
symbol.tsSymbol.valueDeclaration === undefined ||
!ts.isClassDeclaration(symbol.tsSymbol.valueDeclaration)) { !ts.isClassDeclaration(symbol.tsSymbol.valueDeclaration)) {
return null; return null;
} }
@ -314,7 +313,8 @@ export class SymbolBuilder {
// In either case, `_t1["index"]` or `_t1.index`, `node.expression` is _t1. // In either case, `_t1["index"]` or `_t1.index`, `node.expression` is _t1.
// The retrieved symbol for _t1 will be the variable declaration. // The retrieved symbol for _t1 will be the variable declaration.
const tsSymbol = this.getTypeChecker().getSymbolAtLocation(node.expression); 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; return null;
} }
@ -329,8 +329,7 @@ export class SymbolBuilder {
} }
const symbol = this.getSymbolOfTsNode(declaration); const symbol = this.getSymbolOfTsNode(declaration);
if (symbol === null || symbol.tsSymbol === null || if (symbol === null || !isSymbolWithValueDeclaration(symbol.tsSymbol) ||
symbol.tsSymbol.valueDeclaration === undefined ||
!ts.isClassDeclaration(symbol.tsSymbol.valueDeclaration)) { !ts.isClassDeclaration(symbol.tsSymbol.valueDeclaration)) {
return null; return null;
} }
@ -444,7 +443,10 @@ export class SymbolBuilder {
} }
const pipeInstance = this.getSymbolOfTsNode(pipeDeclaration.valueDeclaration); 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; return null;
} }

View File

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

View File

@ -13,6 +13,23 @@ import * as ts from 'typescript';
import {AbsoluteFsPath, getFileSystem} from '../../file_system'; import {AbsoluteFsPath, getFileSystem} from '../../file_system';
import {DeclarationNode} from '../../reflection'; 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 { export function isDtsPath(filePath: string): boolean {
return D_TS.test(filePath); 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 * Note: this check is disabled in g3, search for
* `angularCompilerOptions.disableTypeScriptVersionCheck` config param value in g3. * `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 * 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); 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', () => { describe('strictInputTypes', () => {
beforeEach(() => { beforeEach(() => {
env.write('test.ts', ` env.write('test.ts', `

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -233,6 +233,8 @@ export function getParentRenderElement(view: ViewData, renderHost: any, def: Nod
(renderParent.element!.componentRendererType!.encapsulation === (renderParent.element!.componentRendererType!.encapsulation ===
ViewEncapsulation.ShadowDom || ViewEncapsulation.ShadowDom ||
// TODO(FW-2290): remove the `encapsulation === 1` fallback logic in v12. // 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))) { renderParent.element!.componentRendererType!.encapsulation === 1))) {
// only children of non components, or children of components with native encapsulation should // only children of non components, or children of components with native encapsulation should
// be attached. // be attached.

View File

@ -64,7 +64,7 @@ describe('InjectorDef-based createInjector()', () => {
providedIn: null, providedIn: null,
// ChildService is derived from ServiceWithDep, so the factory function here must do the right // 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. // 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" "node": "^12.14.1 || >=14.0.0"
}, },
"dependencies": { "dependencies": {
"tslib": "^2.1.0" "tslib": "^2.2.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/core": "0.0.0-PLACEHOLDER", "@angular/core": "0.0.0-PLACEHOLDER",

View File

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

View File

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

View File

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

View File

@ -244,7 +244,8 @@ export class LanguageService {
getCompletionEntryDetails( getCompletionEntryDetails(
fileName: string, position: number, entryName: string, fileName: string, position: number, entryName: string,
formatOptions: ts.FormatCodeOptions|ts.FormatCodeSettings|undefined, 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) => { return this.withCompilerAndPerfTracing(PerfPhase.LsCompletions, (compiler) => {
if (!isTemplateContext(compiler.getCurrentProgram(), fileName, position)) { if (!isTemplateContext(compiler.getCurrentProgram(), fileName, position)) {
return undefined; return undefined;
@ -254,7 +255,7 @@ export class LanguageService {
if (builder === null) { if (builder === null) {
return undefined; 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( getCompletionEntryDetails(
entryName: string, formatOptions?: ts.FormatCodeOptions|ts.FormatCodeSettings, 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( return this.ngLS.getCompletionEntryDetails(
this.scriptInfo.fileName, this._cursor, entryName, formatOptions, preferences); this.scriptInfo.fileName, this._cursor, entryName, formatOptions, preferences, data);
} }
getTcb() { getTcb() {
@ -118,4 +119,4 @@ function extractCursorInfo(textWithCursor: string): {cursor: number, text: strin
cursor, cursor,
text: textWithCursor.substr(0, cursor) + textWithCursor.substr(cursor + 1), 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( function getCompletionEntryDetails(
fileName: string, position: number, entryName: string, fileName: string, position: number, entryName: string,
formatOptions: ts.FormatCodeOptions|ts.FormatCodeSettings|undefined, source: string|undefined, 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) { if (angularOnly) {
return ngLS.getCompletionEntryDetails( return ngLS.getCompletionEntryDetails(
fileName, position, entryName, formatOptions, preferences); fileName, position, entryName, formatOptions, preferences, data);
} else { } else {
// If TS could answer the query, then return that result. Otherwise, return from Angular LS. // If TS could answer the query, then return that result. Otherwise, return from Angular LS.
return tsLS.getCompletionEntryDetails( return tsLS.getCompletionEntryDetails(
fileName, position, entryName, formatOptions, source, preferences) ?? fileName, position, entryName, formatOptions, source, preferences, data) ??
ngLS.getCompletionEntryDetails(fileName, position, entryName, formatOptions, preferences); ngLS.getCompletionEntryDetails(
fileName, position, entryName, formatOptions, preferences, data);
} }
} }

View File

@ -88,7 +88,7 @@ export function collectMemberMethods(
const members: ts.MethodDeclaration[] = []; const members: ts.MethodDeclaration[] = [];
const apparentProps = typeChecker.getTypeAtLocation(clazz).getApparentProperties(); const apparentProps = typeChecker.getTypeAtLocation(clazz).getApparentProperties();
for (const prop of apparentProps) { for (const prop of apparentProps) {
if (ts.isMethodDeclaration(prop.valueDeclaration) && prop.valueDeclaration) { if (prop.valueDeclaration && ts.isMethodDeclaration(prop.valueDeclaration)) {
members.push(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) { function allParameterTypesMatch(signature: ts.Signature) {
const tc = context.checker; const tc = context.checker;
return signature.getParameters().every((parameter: ts.Symbol, i: number) => { return signature.getParameters().every((parameter: ts.Symbol, i: number) => {
if (parameter.valueDeclaration === undefined) {
return false;
}
const type = tc.getTypeOfSymbolAtLocation(parameter, parameter.valueDeclaration); const type = tc.getTypeOfSymbolAtLocation(parameter, parameter.valueDeclaration);
return type === passedInTypes[i]; return type === passedInTypes[i];
}); });

View File

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

View File

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

View File

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

View File

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

View File

@ -102,10 +102,15 @@ export class DomRendererFactory2 implements RendererFactory2 {
(<EmulatedEncapsulationDomRenderer2>renderer).applyToHost(element); (<EmulatedEncapsulationDomRenderer2>renderer).applyToHost(element);
return renderer; 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 1:
case ViewEncapsulation.ShadowDom: case ViewEncapsulation.ShadowDom:
// TODO(FW-2290): remove the `case 1:` fallback logic and the warning in v12. // TODO(FW-2290): remove the `case 1:` fallback logic and the warning in v12.
if ((typeof ngDevMode === 'undefined' || ngDevMode) && 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 && type.encapsulation === 1) {
hasLoggedNativeEncapsulationWarning = true; hasLoggedNativeEncapsulationWarning = true;
console.warn( console.warn(

View File

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

View File

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

View File

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

View File

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

View File

@ -28,8 +28,11 @@ if (typeof window !== 'undefined') {
passiveSupported = true; passiveSupported = true;
} }
}); });
window.addEventListener('test', options, options); // Note: We pass the `options` object as the event handler too. This is not compatible with the
window.removeEventListener('test', options, options); // 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) { } catch (err) {
passiveSupported = false; passiveSupported = false;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13330,7 +13330,7 @@ tslib@1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
integrity sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ== 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" version "2.2.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== 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" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d"
integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg== integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==
typescript@4.2.4, typescript@~4.2.4: typescript@4.2.4:
version "4.2.4" version "4.2.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== 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" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.7.tgz#c931733e2ec10dda56b855b379cc488a72a81199"
integrity sha512-MmQdgo/XenfZPvVLtKZOq9jQQvzaUAUpcKW8Z43x9B2fOm4S5g//tPtMweZUIP+SoBqrVPEIm+dJeQ9dfO0QdA== 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: uglify-js@^3.1.4:
version "3.13.8" version "3.13.8"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.8.tgz#7c2f9f2553f611f3ff592bdc19c6fb208dc60afb" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.8.tgz#7c2f9f2553f611f3ff592bdc19c6fb208dc60afb"