feat(compiler-cli): add support for TypeScript 4.0 (#38076)
With this change we add support for TypeScript 4.0 PR Close #38076
This commit is contained in:
parent
201a546af8
commit
0fc44e0436
|
@ -216,7 +216,7 @@ export declare class NgComponentOutlet implements OnChanges, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCheck {
|
export declare class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCheck {
|
||||||
set ngForOf(ngForOf: (U & NgIterable<T>) | undefined | null);
|
set ngForOf(ngForOf: U & NgIterable<T> | undefined | null);
|
||||||
set ngForTemplate(value: TemplateRef<NgForOfContext<T, U>>);
|
set ngForTemplate(value: TemplateRef<NgForOfContext<T, U>>);
|
||||||
set ngForTrackBy(fn: TrackByFunction<T>);
|
set ngForTrackBy(fn: TrackByFunction<T>);
|
||||||
get ngForTrackBy(): TrackByFunction<T>;
|
get ngForTrackBy(): TrackByFunction<T>;
|
||||||
|
|
|
@ -2,7 +2,7 @@ export declare function createCustomElement<P>(component: Type<any>, config: NgE
|
||||||
|
|
||||||
export declare abstract class NgElement extends HTMLElement {
|
export declare abstract class NgElement extends HTMLElement {
|
||||||
protected ngElementEventsSubscription: Subscription | null;
|
protected ngElementEventsSubscription: Subscription | null;
|
||||||
protected ngElementStrategy: NgElementStrategy;
|
protected abstract ngElementStrategy: NgElementStrategy;
|
||||||
abstract attributeChangedCallback(attrName: string, oldValue: string | null, newValue: string, namespace?: string): void;
|
abstract attributeChangedCallback(attrName: string, oldValue: string | null, newValue: string, namespace?: string): void;
|
||||||
abstract connectedCallback(): void;
|
abstract connectedCallback(): void;
|
||||||
abstract disconnectedCallback(): void;
|
abstract disconnectedCallback(): void;
|
||||||
|
|
|
@ -85,6 +85,12 @@ INTEGRATION_TESTS = {
|
||||||
# root @npm//typescript package.
|
# root @npm//typescript package.
|
||||||
"pinned_npm_packages": ["typescript"],
|
"pinned_npm_packages": ["typescript"],
|
||||||
},
|
},
|
||||||
|
"typings_test_ts40": {
|
||||||
|
# Special case for `typings_test_ts40` test as we want to pin
|
||||||
|
# `typescript` at version 4.0.x for that test and not link to the
|
||||||
|
# root @npm//typescript package.
|
||||||
|
"pinned_npm_packages": ["typescript"],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
[
|
[
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* @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 platformServerTesting from '@angular/platform-server/testing';
|
||||||
|
import * as platformWebworker from '@angular/platform-webworker';
|
||||||
|
import * as platformWebworkerDynamic from '@angular/platform-webworker-dynamic';
|
||||||
|
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,
|
||||||
|
platformServerTesting,
|
||||||
|
platformWebworker,
|
||||||
|
platformWebworkerDynamic,
|
||||||
|
router,
|
||||||
|
routerTesting,
|
||||||
|
routerUpgrade,
|
||||||
|
serviceWorker,
|
||||||
|
upgrade,
|
||||||
|
upgradeStatic,
|
||||||
|
upgradeTesting,
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"name": "angular-integration",
|
||||||
|
"description": "Assert that users with TypeScript 4.0 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/platform-webworker": "file:../../dist/packages-dist/platform-webworker",
|
||||||
|
"@angular/platform-webworker-dynamic": "file:../../dist/packages-dist/platform-webworker-dynamic",
|
||||||
|
"@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.0.2",
|
||||||
|
"zone.js": "file:../../dist/zone.js-dist/zone.js"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "tsc"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"outDir": "./dist/out-tsc",
|
||||||
|
"rootDir": ".",
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [
|
||||||
|
"es5",
|
||||||
|
"dom",
|
||||||
|
"es2015.collection",
|
||||||
|
"es2015.iterable",
|
||||||
|
"es2015.promise"
|
||||||
|
],
|
||||||
|
"types": [],
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"include-all.ts",
|
||||||
|
"node_modules/@types/jasmine/index.d.ts"
|
||||||
|
]
|
||||||
|
}
|
|
@ -149,8 +149,8 @@
|
||||||
"terser": "^4.4.0",
|
"terser": "^4.4.0",
|
||||||
"tsickle": "0.38.1",
|
"tsickle": "0.38.1",
|
||||||
"tslib": "^2.0.0",
|
"tslib": "^2.0.0",
|
||||||
"tslint": "6.0.0",
|
"tslint": "6.1.3",
|
||||||
"typescript": "~3.9.5",
|
"typescript": "~4.0.2",
|
||||||
"xhr2": "0.2.0",
|
"xhr2": "0.2.0",
|
||||||
"yaml": "^1.7.2",
|
"yaml": "^1.7.2",
|
||||||
"yargs": "^15.4.1"
|
"yargs": "^15.4.1"
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
"@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": ">=3.9 <4.0",
|
"typescript": ">=3.9 <4.1",
|
||||||
"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",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@angular/compiler": "0.0.0-PLACEHOLDER",
|
"@angular/compiler": "0.0.0-PLACEHOLDER",
|
||||||
"typescript": ">=3.9 <4.0"
|
"typescript": ">=3.9 <4.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0"
|
"node": ">=10.0"
|
||||||
|
|
|
@ -476,13 +476,16 @@ export class Evaluator {
|
||||||
return recordEntry(typeReference, node);
|
return recordEntry(typeReference, node);
|
||||||
case ts.SyntaxKind.UnionType:
|
case ts.SyntaxKind.UnionType:
|
||||||
const unionType = <ts.UnionTypeNode>node;
|
const unionType = <ts.UnionTypeNode>node;
|
||||||
|
|
||||||
// Remove null and undefined from the list of unions.
|
// Remove null and undefined from the list of unions.
|
||||||
const references = unionType.types
|
// TODO(alan-agius4): remove `n.kind !== ts.SyntaxKind.NullKeyword` when
|
||||||
.filter(
|
// TS 3.9 support is dropped. In TS 4.0 NullKeyword is a child of LiteralType.
|
||||||
n => n.kind != ts.SyntaxKind.NullKeyword &&
|
const references =
|
||||||
n.kind != ts.SyntaxKind.UndefinedKeyword)
|
unionType.types
|
||||||
.map(n => this.evaluateNode(n));
|
.filter(
|
||||||
|
n => n.kind !== ts.SyntaxKind.NullKeyword &&
|
||||||
|
n.kind !== ts.SyntaxKind.UndefinedKeyword &&
|
||||||
|
!(ts.isLiteralTypeNode(n) && n.literal.kind === ts.SyntaxKind.NullKeyword))
|
||||||
|
.map(n => this.evaluateNode(n));
|
||||||
|
|
||||||
// The remmaining reference must be the same. If two have type arguments consider them
|
// The remmaining reference must be the same. If two have type arguments consider them
|
||||||
// different even if the type arguments are the same.
|
// different even if the type arguments are the same.
|
||||||
|
|
|
@ -62,8 +62,8 @@ export class Symbols {
|
||||||
// even if the `SourceFile` was not type checked (which looks for `SourceFile`
|
// even if the `SourceFile` was not type checked (which looks for `SourceFile`
|
||||||
// in the parent chain). This doesn't damage the node as the binder unconditionally
|
// in the parent chain). This doesn't damage the node as the binder unconditionally
|
||||||
// sets the parent.
|
// sets the parent.
|
||||||
externalReference.expression.parent = externalReference;
|
(externalReference.expression.parent as ts.Node) = externalReference;
|
||||||
externalReference.parent = this.sourceFile as any;
|
(externalReference.parent as ts.Node) = this.sourceFile;
|
||||||
}
|
}
|
||||||
const from = stripQuotes(externalReference.expression.getText());
|
const from = stripQuotes(externalReference.expression.getText());
|
||||||
symbols.set(
|
symbols.set(
|
||||||
|
@ -83,8 +83,8 @@ export class Symbols {
|
||||||
}
|
}
|
||||||
if (!importDecl.moduleSpecifier.parent) {
|
if (!importDecl.moduleSpecifier.parent) {
|
||||||
// See note above in the `ImportEqualDeclaration` case.
|
// See note above in the `ImportEqualDeclaration` case.
|
||||||
importDecl.moduleSpecifier.parent = importDecl;
|
(importDecl.moduleSpecifier.parent as ts.Node) = importDecl;
|
||||||
importDecl.parent = this.sourceFile;
|
(importDecl.parent as ts.Node) = this.sourceFile;
|
||||||
}
|
}
|
||||||
const from = stripQuotes(importDecl.moduleSpecifier.getText());
|
const from = stripQuotes(importDecl.moduleSpecifier.getText());
|
||||||
if (importDecl.importClause.name) {
|
if (importDecl.importClause.name) {
|
||||||
|
|
|
@ -20,22 +20,26 @@ export function extractReferencesFromType(
|
||||||
if (!ts.isTupleTypeNode(def)) {
|
if (!ts.isTupleTypeNode(def)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return def.elementTypes.map(element => {
|
|
||||||
if (!ts.isTypeQueryNode(element)) {
|
// TODO(alan-agius4): remove `def.elementTypes` and casts when TS 3.9 support is dropped and G3 is
|
||||||
throw new Error(`Expected TypeQueryNode: ${nodeDebugInfo(element)}`);
|
// using TS 4.0.
|
||||||
}
|
return (((def as any).elements || (def as any).elementTypes) as ts.NodeArray<ts.TypeNode>)
|
||||||
const type = element.exprName;
|
.map(element => {
|
||||||
const {node, from} = reflectTypeEntityToDeclaration(type, checker);
|
if (!ts.isTypeQueryNode(element)) {
|
||||||
if (!isNamedClassDeclaration(node)) {
|
throw new Error(`Expected TypeQueryNode: ${nodeDebugInfo(element)}`);
|
||||||
throw new Error(`Expected named ClassDeclaration: ${nodeDebugInfo(node)}`);
|
}
|
||||||
}
|
const type = element.exprName;
|
||||||
const specifier = (from !== null && !from.startsWith('.') ? from : ngModuleImportedFrom);
|
const {node, from} = reflectTypeEntityToDeclaration(type, checker);
|
||||||
if (specifier !== null) {
|
if (!isNamedClassDeclaration(node)) {
|
||||||
return new Reference(node, {specifier, resolutionContext});
|
throw new Error(`Expected named ClassDeclaration: ${nodeDebugInfo(node)}`);
|
||||||
} else {
|
}
|
||||||
return new Reference(node);
|
const specifier = (from !== null && !from.startsWith('.') ? from : ngModuleImportedFrom);
|
||||||
}
|
if (specifier !== null) {
|
||||||
});
|
return new Reference(node, {specifier, resolutionContext});
|
||||||
|
} else {
|
||||||
|
return new Reference(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readStringType(type: ts.TypeNode): string|null {
|
export function readStringType(type: ts.TypeNode): string|null {
|
||||||
|
@ -69,12 +73,15 @@ export function readStringArrayType(type: ts.TypeNode): string[] {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const res: string[] = [];
|
const res: string[] = [];
|
||||||
type.elementTypes.forEach(el => {
|
// TODO(alan-agius4): remove `def.elementTypes` and casts when TS 3.9 support is dropped and G3 is
|
||||||
if (!ts.isLiteralTypeNode(el) || !ts.isStringLiteral(el.literal)) {
|
// using TS 4.0.
|
||||||
return;
|
(((type as any).elements || (type as any).elementTypes) as ts.NodeArray<ts.TypeNode>)
|
||||||
}
|
.forEach(el => {
|
||||||
res.push(el.literal.text);
|
if (!ts.isLiteralTypeNode(el) || !ts.isStringLiteral(el.literal)) {
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
res.push(el.literal.text);
|
||||||
|
});
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,11 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
||||||
// optional tokes that don't have providers.
|
// optional tokes that don't have providers.
|
||||||
if (typeNode && ts.isUnionTypeNode(typeNode)) {
|
if (typeNode && ts.isUnionTypeNode(typeNode)) {
|
||||||
let childTypeNodes = typeNode.types.filter(
|
let childTypeNodes = typeNode.types.filter(
|
||||||
childTypeNode => childTypeNode.kind !== ts.SyntaxKind.NullKeyword);
|
// TODO(alan-agius4): remove `childTypeNode.kind !== ts.SyntaxKind.NullKeyword` when
|
||||||
|
// TS 3.9 support is dropped. In TS 4.0 NullKeyword is a child of LiteralType.
|
||||||
|
childTypeNode => childTypeNode.kind !== ts.SyntaxKind.NullKeyword &&
|
||||||
|
!(ts.isLiteralTypeNode(childTypeNode) &&
|
||||||
|
childTypeNode.literal.kind === ts.SyntaxKind.NullKeyword));
|
||||||
|
|
||||||
if (childTypeNodes.length === 1) {
|
if (childTypeNodes.length === 1) {
|
||||||
typeNode = childTypeNodes[0];
|
typeNode = childTypeNodes[0];
|
||||||
|
|
|
@ -128,8 +128,6 @@ function transformFactorySourceFile(
|
||||||
|
|
||||||
const {moduleSymbols, sourceFilePath} = factoryMap.get(file.fileName)!;
|
const {moduleSymbols, sourceFilePath} = factoryMap.get(file.fileName)!;
|
||||||
|
|
||||||
file = ts.getMutableClone(file);
|
|
||||||
|
|
||||||
// Not every exported factory statement is valid. They were generated before the program was
|
// Not every exported factory statement is valid. They were generated before the program was
|
||||||
// analyzed, and before ngtsc knew which symbols were actually NgModules. factoryMap contains
|
// analyzed, and before ngtsc knew which symbols were actually NgModules. factoryMap contains
|
||||||
// that knowledge now, so this transform filters the statement list and removes exported factories
|
// that knowledge now, so this transform filters the statement list and removes exported factories
|
||||||
|
@ -221,7 +219,8 @@ function transformFactorySourceFile(
|
||||||
// satisfy closure compiler.
|
// satisfy closure compiler.
|
||||||
transformedStatements.push(nonEmptyExport);
|
transformedStatements.push(nonEmptyExport);
|
||||||
}
|
}
|
||||||
file.statements = ts.createNodeArray(transformedStatements);
|
|
||||||
|
file = ts.updateSourceFileNode(file, transformedStatements);
|
||||||
|
|
||||||
// If any imports to @angular/core were detected and rewritten (which happens when compiling
|
// If any imports to @angular/core were detected and rewritten (which happens when compiling
|
||||||
// @angular/core), go through the SourceFile and rewrite references to symbols imported from core.
|
// @angular/core), go through the SourceFile and rewrite references to symbols imported from core.
|
||||||
|
|
|
@ -42,8 +42,7 @@ function flipIvySwitchInFile(sf: ts.SourceFile): ts.SourceFile {
|
||||||
|
|
||||||
// Only update the statements in the SourceFile if any have changed.
|
// Only update the statements in the SourceFile if any have changed.
|
||||||
if (newStatements !== undefined) {
|
if (newStatements !== undefined) {
|
||||||
sf = ts.getMutableClone(sf);
|
return ts.updateSourceFileNode(sf, newStatements);
|
||||||
sf.statements = ts.createNodeArray(newStatements);
|
|
||||||
}
|
}
|
||||||
return sf;
|
return sf;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +104,7 @@ function flipIvySwitchesInVariableStatement(
|
||||||
|
|
||||||
// Find the post-switch variable identifier. If one can't be found, it's an error. This is
|
// Find the post-switch variable identifier. If one can't be found, it's an error. This is
|
||||||
// reported as a thrown error and not a diagnostic as transformers cannot output diagnostics.
|
// reported as a thrown error and not a diagnostic as transformers cannot output diagnostics.
|
||||||
let newIdentifier = findPostSwitchIdentifier(statements, postSwitchName);
|
const newIdentifier = findPostSwitchIdentifier(statements, postSwitchName);
|
||||||
if (newIdentifier === null) {
|
if (newIdentifier === null) {
|
||||||
throw new Error(`Unable to find identifier ${postSwitchName} in ${
|
throw new Error(`Unable to find identifier ${postSwitchName} in ${
|
||||||
stmt.getSourceFile().fileName} for the Ivy switch.`);
|
stmt.getSourceFile().fileName} for the Ivy switch.`);
|
||||||
|
|
|
@ -28,9 +28,7 @@ export function aliasTransformFactory(exportStatements: Map<string, Map<string,
|
||||||
statements.push(stmt);
|
statements.push(stmt);
|
||||||
});
|
});
|
||||||
|
|
||||||
file = ts.getMutableClone(file);
|
return ts.updateSourceFileNode(file, statements);
|
||||||
file.statements = ts.createNodeArray(statements);
|
|
||||||
return file;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,32 +239,48 @@ export class ReturnTypeTransform implements DtsTransform {
|
||||||
}
|
}
|
||||||
|
|
||||||
transformClassElement(element: ts.ClassElement, imports: ImportManager): ts.ClassElement {
|
transformClassElement(element: ts.ClassElement, imports: ImportManager): ts.ClassElement {
|
||||||
if (!ts.isMethodSignature(element)) {
|
// // TODO(alan-agius4): Remove when we no longer support TS 3.9
|
||||||
return element;
|
// TS <= 3.9
|
||||||
|
if (ts.isMethodSignature(element)) {
|
||||||
|
const original = ts.getOriginalNode(element) as ts.MethodDeclaration;
|
||||||
|
if (!this.typeReplacements.has(original)) {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
const returnType = this.typeReplacements.get(original)!;
|
||||||
|
const tsReturnType = translateType(returnType, imports);
|
||||||
|
const methodSignature = ts.updateMethodSignature(
|
||||||
|
/* node */ element,
|
||||||
|
/* typeParameters */ element.typeParameters,
|
||||||
|
/* parameters */ element.parameters,
|
||||||
|
/* type */ tsReturnType,
|
||||||
|
/* name */ element.name,
|
||||||
|
/* questionToken */ element.questionToken);
|
||||||
|
|
||||||
|
// Copy over any modifiers, these cannot be set during the `ts.updateMethodSignature` call.
|
||||||
|
(methodSignature.modifiers as ts.ModifiersArray | undefined) = element.modifiers;
|
||||||
|
|
||||||
|
// A bug in the TypeScript declaration causes `ts.MethodSignature` not to be assignable to
|
||||||
|
// `ts.ClassElement`. Since `element` was a `ts.MethodSignature` already, transforming it into
|
||||||
|
// this type is actually correct.
|
||||||
|
return methodSignature as unknown as ts.ClassElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
const original = ts.getOriginalNode(element) as ts.MethodDeclaration;
|
// TS 4.0 +
|
||||||
if (!this.typeReplacements.has(original)) {
|
if (ts.isMethodDeclaration(element)) {
|
||||||
return element;
|
const original = ts.getOriginalNode(element, ts.isMethodDeclaration);
|
||||||
|
if (!this.typeReplacements.has(original)) {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
const returnType = this.typeReplacements.get(original)!;
|
||||||
|
const tsReturnType = translateType(returnType, imports);
|
||||||
|
|
||||||
|
return ts.updateMethod(
|
||||||
|
element, element.decorators, element.modifiers, element.asteriskToken, element.name,
|
||||||
|
element.questionToken, element.typeParameters, element.parameters, tsReturnType,
|
||||||
|
element.body);
|
||||||
}
|
}
|
||||||
const returnType = this.typeReplacements.get(original)!;
|
|
||||||
const tsReturnType = translateType(returnType, imports);
|
|
||||||
|
|
||||||
const methodSignature = ts.updateMethodSignature(
|
return element;
|
||||||
/* node */ element,
|
|
||||||
/* typeParameters */ element.typeParameters,
|
|
||||||
/* parameters */ element.parameters,
|
|
||||||
/* type */ tsReturnType,
|
|
||||||
/* name */ element.name,
|
|
||||||
/* questionToken */ element.questionToken);
|
|
||||||
|
|
||||||
// Copy over any modifiers, these cannot be set during the `ts.updateMethodSignature` call.
|
|
||||||
methodSignature.modifiers = element.modifiers;
|
|
||||||
|
|
||||||
// A bug in the TypeScript declaration causes `ts.MethodSignature` not to be assignable to
|
|
||||||
// `ts.ClassElement`. Since `element` was a `ts.MethodSignature` already, transforming it into
|
|
||||||
// this type is actually correct.
|
|
||||||
return methodSignature as unknown as ts.ClassElement;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
transformFunctionDeclaration(element: ts.FunctionDeclaration, imports: ImportManager):
|
transformFunctionDeclaration(element: ts.FunctionDeclaration, imports: ImportManager):
|
||||||
|
|
|
@ -187,8 +187,8 @@ class IvyTransformationVisitor extends Visitor {
|
||||||
|
|
||||||
// Create a new `NodeArray` with the filtered decorators that sourcemaps back to the original.
|
// Create a new `NodeArray` with the filtered decorators that sourcemaps back to the original.
|
||||||
const array = ts.createNodeArray(filtered);
|
const array = ts.createNodeArray(filtered);
|
||||||
array.pos = node.decorators.pos;
|
(array.pos as number) = node.decorators.pos;
|
||||||
array.end = node.decorators.end;
|
(array.end as number) = node.decorators.end;
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,9 @@ export function addImports(
|
||||||
// for @fileoverview Closure annotation. If there is no @fileoverview annotations, this
|
// for @fileoverview Closure annotation. If there is no @fileoverview annotations, this
|
||||||
// statement would be a noop.
|
// statement would be a noop.
|
||||||
const fileoverviewAnchorStmt = ts.createNotEmittedStatement(sf);
|
const fileoverviewAnchorStmt = ts.createNotEmittedStatement(sf);
|
||||||
sf.statements = ts.createNodeArray(
|
return ts.updateSourceFileNode(sf, ts.createNodeArray([
|
||||||
[fileoverviewAnchorStmt, ...existingImports, ...addedImports, ...extraStatements, ...body]);
|
fileoverviewAnchorStmt, ...existingImports, ...addedImports, ...extraStatements, ...body
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sf;
|
return sf;
|
||||||
|
|
|
@ -526,7 +526,11 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor {
|
||||||
|
|
||||||
visitLiteralExpr(ast: LiteralExpr, context: Context): ts.TypeNode {
|
visitLiteralExpr(ast: LiteralExpr, context: Context): ts.TypeNode {
|
||||||
if (ast.value === null) {
|
if (ast.value === null) {
|
||||||
return ts.createKeywordTypeNode(ts.SyntaxKind.NullKeyword);
|
// TODO(alan-agius4): Remove when we no longer support TS 3.9
|
||||||
|
// Use: return ts.createLiteralTypeNode(ts.createNull()) directly.
|
||||||
|
return ts.versionMajorMinor.charAt(0) === '4' ?
|
||||||
|
ts.createLiteralTypeNode(ts.createNull() as any) :
|
||||||
|
ts.createKeywordTypeNode(ts.SyntaxKind.NullKeyword as any);
|
||||||
} else if (ast.value === undefined) {
|
} else if (ast.value === undefined) {
|
||||||
return ts.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword);
|
return ts.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword);
|
||||||
} else if (typeof ast.value === 'boolean') {
|
} else if (typeof ast.value === 'boolean') {
|
||||||
|
@ -696,7 +700,7 @@ function createLocalizedStringTaggedTemplate(
|
||||||
// Revert once https://github.com/microsoft/TypeScript/issues/35374 is fixed
|
// Revert once https://github.com/microsoft/TypeScript/issues/35374 is fixed
|
||||||
function createTemplateMiddle(cooked: string, raw: string): ts.TemplateMiddle {
|
function createTemplateMiddle(cooked: string, raw: string): ts.TemplateMiddle {
|
||||||
const node: ts.TemplateLiteralLikeNode = ts.createTemplateHead(cooked, raw);
|
const node: ts.TemplateLiteralLikeNode = ts.createTemplateHead(cooked, raw);
|
||||||
node.kind = ts.SyntaxKind.TemplateMiddle;
|
(node.kind as ts.SyntaxKind) = ts.SyntaxKind.TemplateMiddle;
|
||||||
return node as ts.TemplateMiddle;
|
return node as ts.TemplateMiddle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -704,7 +708,7 @@ function createTemplateMiddle(cooked: string, raw: string): ts.TemplateMiddle {
|
||||||
// Revert once https://github.com/microsoft/TypeScript/issues/35374 is fixed
|
// Revert once https://github.com/microsoft/TypeScript/issues/35374 is fixed
|
||||||
function createTemplateTail(cooked: string, raw: string): ts.TemplateTail {
|
function createTemplateTail(cooked: string, raw: string): ts.TemplateTail {
|
||||||
const node: ts.TemplateLiteralLikeNode = ts.createTemplateHead(cooked, raw);
|
const node: ts.TemplateLiteralLikeNode = ts.createTemplateHead(cooked, raw);
|
||||||
node.kind = ts.SyntaxKind.TemplateTail;
|
(node.kind as ts.SyntaxKind) = ts.SyntaxKind.TemplateTail;
|
||||||
return node as ts.TemplateTail;
|
return node as ts.TemplateTail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ export function canEmitType(type: ts.TypeNode, resolver: TypeReferenceResolver):
|
||||||
visitTypeReferenceNode: type => canEmitTypeReference(type),
|
visitTypeReferenceNode: type => canEmitTypeReference(type),
|
||||||
visitArrayTypeNode: type => canEmitTypeWorker(type.elementType),
|
visitArrayTypeNode: type => canEmitTypeWorker(type.elementType),
|
||||||
visitKeywordType: () => true,
|
visitKeywordType: () => true,
|
||||||
|
visitLiteralType: () => true,
|
||||||
visitOtherType: () => false,
|
visitOtherType: () => false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -111,6 +112,7 @@ export class TypeEmitter {
|
||||||
visitTypeReferenceNode: type => this.emitTypeReference(type),
|
visitTypeReferenceNode: type => this.emitTypeReference(type),
|
||||||
visitArrayTypeNode: type => ts.updateArrayTypeNode(type, this.emitType(type.elementType)),
|
visitArrayTypeNode: type => ts.updateArrayTypeNode(type, this.emitType(type.elementType)),
|
||||||
visitKeywordType: type => type,
|
visitKeywordType: type => type,
|
||||||
|
visitLiteralType: type => type,
|
||||||
visitOtherType: () => {
|
visitOtherType: () => {
|
||||||
throw new Error('Unable to emit a complex type');
|
throw new Error('Unable to emit a complex type');
|
||||||
},
|
},
|
||||||
|
@ -159,6 +161,7 @@ interface TypeEmitterVisitor<R> {
|
||||||
visitTypeReferenceNode(type: ts.TypeReferenceNode): R;
|
visitTypeReferenceNode(type: ts.TypeReferenceNode): R;
|
||||||
visitArrayTypeNode(type: ts.ArrayTypeNode): R;
|
visitArrayTypeNode(type: ts.ArrayTypeNode): R;
|
||||||
visitKeywordType(type: ts.KeywordTypeNode): R;
|
visitKeywordType(type: ts.KeywordTypeNode): R;
|
||||||
|
visitLiteralType(type: ts.LiteralTypeNode): R;
|
||||||
visitOtherType(type: ts.TypeNode): R;
|
visitOtherType(type: ts.TypeNode): R;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +170,8 @@ function visitTypeNode<R>(type: ts.TypeNode, visitor: TypeEmitterVisitor<R>): R
|
||||||
return visitor.visitTypeReferenceNode(type);
|
return visitor.visitTypeReferenceNode(type);
|
||||||
} else if (ts.isArrayTypeNode(type)) {
|
} else if (ts.isArrayTypeNode(type)) {
|
||||||
return visitor.visitArrayTypeNode(type);
|
return visitor.visitArrayTypeNode(type);
|
||||||
|
} else if (ts.isLiteralTypeNode(type)) {
|
||||||
|
return visitor.visitLiteralType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type.kind) {
|
switch (type.kind) {
|
||||||
|
|
|
@ -456,7 +456,7 @@ class TestComponent {
|
||||||
}`);
|
}`);
|
||||||
|
|
||||||
expect(messages).toEqual(
|
expect(messages).toEqual(
|
||||||
[`TestComponent.html(1, 15): Type '2' is not assignable to type 'string'.`]);
|
[`TestComponent.html(1, 15): Type 'number' is not assignable to type 'string'.`]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -140,10 +140,16 @@ function createCtorParametersClassPropertyType(): ts.TypeNode {
|
||||||
undefined),
|
undefined),
|
||||||
])),
|
])),
|
||||||
undefined));
|
undefined));
|
||||||
return ts.createFunctionTypeNode(
|
|
||||||
undefined, [],
|
// TODO(alan-agius4): Remove when we no longer support TS 3.9
|
||||||
ts.createArrayTypeNode(
|
const nullLiteral = ts.createNull() as any;
|
||||||
ts.createUnionTypeNode([ts.createTypeLiteralNode(typeElements), ts.createNull()])));
|
const nullType = ts.versionMajorMinor.charAt(0) === '4' ?
|
||||||
|
ts.createLiteralTypeNode(nullLiteral as any) :
|
||||||
|
nullLiteral;
|
||||||
|
return ts.createFunctionTypeNode(undefined, [], ts.createArrayTypeNode(ts.createUnionTypeNode([
|
||||||
|
ts.createTypeLiteralNode(typeElements),
|
||||||
|
nullType,
|
||||||
|
])));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -287,8 +293,13 @@ function typeReferenceToExpression(
|
||||||
// Ignore any generic types, just return the base type.
|
// Ignore any generic types, just return the base type.
|
||||||
return entityNameToExpression(typeRef.typeName);
|
return entityNameToExpression(typeRef.typeName);
|
||||||
case ts.SyntaxKind.UnionType:
|
case ts.SyntaxKind.UnionType:
|
||||||
|
// TODO(alan-agius4): remove `t.kind !== ts.SyntaxKind.NullKeyword` when
|
||||||
|
// TS 3.9 support is dropped. In TS 4.0 NullKeyword is a child of LiteralType.
|
||||||
const childTypeNodes =
|
const childTypeNodes =
|
||||||
(node as ts.UnionTypeNode).types.filter(t => t.kind !== ts.SyntaxKind.NullKeyword);
|
(node as ts.UnionTypeNode)
|
||||||
|
.types.filter(
|
||||||
|
t => t.kind !== ts.SyntaxKind.NullKeyword &&
|
||||||
|
!(ts.isLiteralTypeNode(t) && t.literal.kind === ts.SyntaxKind.NullKeyword));
|
||||||
return childTypeNodes.length === 1 ?
|
return childTypeNodes.length === 1 ?
|
||||||
typeReferenceToExpression(entityNameToExpression, childTypeNodes[0]) :
|
typeReferenceToExpression(entityNameToExpression, childTypeNodes[0]) :
|
||||||
undefined;
|
undefined;
|
||||||
|
@ -434,7 +445,7 @@ export function getDownlevelDecoratorsTransform(
|
||||||
|
|
||||||
const name = (element.name as ts.Identifier).text;
|
const name = (element.name as ts.Identifier).text;
|
||||||
const mutable = ts.getMutableClone(element);
|
const mutable = ts.getMutableClone(element);
|
||||||
mutable.decorators = decoratorsToKeep.length ?
|
(mutable as any).decorators = decoratorsToKeep.length ?
|
||||||
ts.setTextRange(ts.createNodeArray(decoratorsToKeep), mutable.decorators) :
|
ts.setTextRange(ts.createNodeArray(decoratorsToKeep), mutable.decorators) :
|
||||||
undefined;
|
undefined;
|
||||||
return [name, mutable, toLower];
|
return [name, mutable, toLower];
|
||||||
|
@ -551,8 +562,6 @@ export function getDownlevelDecoratorsTransform(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const newClassDeclaration = ts.getMutableClone(classDecl);
|
|
||||||
|
|
||||||
if (decoratorsToLower.length) {
|
if (decoratorsToLower.length) {
|
||||||
newMembers.push(createDecoratorClassProperty(decoratorsToLower));
|
newMembers.push(createDecoratorClassProperty(decoratorsToLower));
|
||||||
}
|
}
|
||||||
|
@ -567,12 +576,13 @@ export function getDownlevelDecoratorsTransform(
|
||||||
if (decoratedProperties.size) {
|
if (decoratedProperties.size) {
|
||||||
newMembers.push(createPropDecoratorsClassProperty(diagnostics, decoratedProperties));
|
newMembers.push(createPropDecoratorsClassProperty(diagnostics, decoratedProperties));
|
||||||
}
|
}
|
||||||
newClassDeclaration.members = ts.setTextRange(
|
|
||||||
ts.createNodeArray(newMembers, newClassDeclaration.members.hasTrailingComma),
|
const members = ts.setTextRange(
|
||||||
classDecl.members);
|
ts.createNodeArray(newMembers, classDecl.members.hasTrailingComma), classDecl.members);
|
||||||
newClassDeclaration.decorators =
|
|
||||||
decoratorsToKeep.length ? ts.createNodeArray(decoratorsToKeep) : undefined;
|
return ts.updateClassDeclaration(
|
||||||
return newClassDeclaration;
|
classDecl, decoratorsToKeep.length ? decoratorsToKeep : undefined, classDecl.modifiers,
|
||||||
|
classDecl.name, classDecl.typeParameters, classDecl.heritageClauses, members);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -167,14 +167,13 @@ function transformSourceFile(
|
||||||
|
|
||||||
newStatements = tmpStatements;
|
newStatements = tmpStatements;
|
||||||
}
|
}
|
||||||
// Note: We cannot use ts.updateSourcefile here as
|
|
||||||
// it does not work well with decorators.
|
const newSf = ts.updateSourceFileNode(
|
||||||
// See https://github.com/Microsoft/TypeScript/issues/17384
|
sourceFile, ts.setTextRange(ts.createNodeArray(newStatements), sourceFile.statements));
|
||||||
const newSf = ts.getMutableClone(sourceFile);
|
|
||||||
if (!(sourceFile.flags & ts.NodeFlags.Synthesized)) {
|
if (!(sourceFile.flags & ts.NodeFlags.Synthesized)) {
|
||||||
newSf.flags &= ~ts.NodeFlags.Synthesized;
|
(newSf.flags as ts.NodeFlags) &= ~ts.NodeFlags.Synthesized;
|
||||||
}
|
}
|
||||||
newSf.statements = ts.setTextRange(ts.createNodeArray(newStatements), sourceFile.statements);
|
|
||||||
return newSf;
|
return newSf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,11 +208,6 @@ export interface RequestsMap {
|
||||||
getRequests(sourceFile: ts.SourceFile): RequestLocationMap;
|
getRequests(sourceFile: ts.SourceFile): RequestLocationMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MetadataAndLoweringRequests {
|
|
||||||
metadata: ModuleMetadata|undefined;
|
|
||||||
requests: RequestLocationMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isEligibleForLowering(node: ts.Node|undefined): boolean {
|
function isEligibleForLowering(node: ts.Node|undefined): boolean {
|
||||||
if (node) {
|
if (node) {
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
|
|
|
@ -19,7 +19,7 @@ const MIN_TS_VERSION = '3.9.2';
|
||||||
* ∀ supported typescript version v, v < MAX_TS_VERSION
|
* ∀ supported typescript version v, v < MAX_TS_VERSION
|
||||||
* MAX_TS_VERSION is not considered as a supported TypeScript version
|
* MAX_TS_VERSION is not considered as a supported TypeScript version
|
||||||
*/
|
*/
|
||||||
const MAX_TS_VERSION = '4.0.0';
|
const MAX_TS_VERSION = '4.1.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
|
||||||
|
|
|
@ -787,7 +787,7 @@ describe('ng type checker', () => {
|
||||||
it('should report an invalid call to a pipe', () => {
|
it('should report an invalid call to a pipe', () => {
|
||||||
rejectOnlyWithFullTemplateTypeCheck(
|
rejectOnlyWithFullTemplateTypeCheck(
|
||||||
'<div>{{"hello" | aPipe}}</div>',
|
'<div>{{"hello" | aPipe}}</div>',
|
||||||
`Argument of type '"hello"' is not assignable to parameter of type 'number'.`, '0:5');
|
`Argument of type 'string' is not assignable to parameter of type 'number'.`, '0:5');
|
||||||
});
|
});
|
||||||
it('should report an invalid property on an exportAs directive', () => {
|
it('should report an invalid property on an exportAs directive', () => {
|
||||||
rejectOnlyWithFullTemplateTypeCheck(
|
rejectOnlyWithFullTemplateTypeCheck(
|
||||||
|
|
|
@ -136,7 +136,7 @@ export declare class AnimationEvent {
|
||||||
|
|
||||||
const diags = env.driveDiagnostics();
|
const diags = env.driveDiagnostics();
|
||||||
expect(diags.length).toBe(1);
|
expect(diags.length).toBe(1);
|
||||||
expect(diags[0].messageText).toEqual(`Type '"2"' is not assignable to type 'number'.`);
|
expect(diags[0].messageText).toEqual(`Type 'string' is not assignable to type 'number'.`);
|
||||||
// The reported error code should be in the TS error space, not a -99 "NG" code.
|
// The reported error code should be in the TS error space, not a -99 "NG" code.
|
||||||
expect(diags[0].code).toBeGreaterThan(0);
|
expect(diags[0].code).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
@ -168,8 +168,8 @@ export declare class AnimationEvent {
|
||||||
|
|
||||||
const diags = env.driveDiagnostics();
|
const diags = env.driveDiagnostics();
|
||||||
expect(diags.length).toBe(2);
|
expect(diags.length).toBe(2);
|
||||||
expect(diags[0].messageText).toEqual(`Type '"2"' is not assignable to type 'number'.`);
|
expect(diags[0].messageText).toEqual(`Type 'string' is not assignable to type 'number'.`);
|
||||||
expect(diags[1].messageText).toEqual(`Type '"2"' is not assignable to type 'number'.`);
|
expect(diags[1].messageText).toEqual(`Type 'string' is not assignable to type 'number'.`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support inputs and outputs with names that are not JavaScript identifiers', () => {
|
it('should support inputs and outputs with names that are not JavaScript identifiers', () => {
|
||||||
|
@ -204,7 +204,7 @@ export declare class AnimationEvent {
|
||||||
|
|
||||||
const diags = env.driveDiagnostics();
|
const diags = env.driveDiagnostics();
|
||||||
expect(diags.length).toBe(2);
|
expect(diags.length).toBe(2);
|
||||||
expect(diags[0].messageText).toEqual(`Type '2' is not assignable to type 'string'.`);
|
expect(diags[0].messageText).toEqual(`Type 'number' is not assignable to type 'string'.`);
|
||||||
expect(diags[1].messageText)
|
expect(diags[1].messageText)
|
||||||
.toEqual(`Argument of type 'string' is not assignable to parameter of type 'number'.`);
|
.toEqual(`Argument of type 'string' is not assignable to parameter of type 'number'.`);
|
||||||
});
|
});
|
||||||
|
@ -380,7 +380,7 @@ export declare class AnimationEvent {
|
||||||
|
|
||||||
const diags = env.driveDiagnostics();
|
const diags = env.driveDiagnostics();
|
||||||
expect(diags.length).toBe(2);
|
expect(diags.length).toBe(2);
|
||||||
expect(diags[0].messageText).toEqual(`Type '1' is not assignable to type 'string'.`);
|
expect(diags[0].messageText).toEqual(`Type 'number' is not assignable to type 'string'.`);
|
||||||
expect(diags[1].messageText)
|
expect(diags[1].messageText)
|
||||||
.toEqual(`Property 'invalid' does not exist on type 'TestCmp'.`);
|
.toEqual(`Property 'invalid' does not exist on type 'TestCmp'.`);
|
||||||
});
|
});
|
||||||
|
@ -390,7 +390,7 @@ export declare class AnimationEvent {
|
||||||
|
|
||||||
const diags = env.driveDiagnostics();
|
const diags = env.driveDiagnostics();
|
||||||
expect(diags.length).toBe(2);
|
expect(diags.length).toBe(2);
|
||||||
expect(diags[0].messageText).toEqual(`Type '1' is not assignable to type 'string'.`);
|
expect(diags[0].messageText).toEqual(`Type 'number' is not assignable to type 'string'.`);
|
||||||
expect(diags[1].messageText)
|
expect(diags[1].messageText)
|
||||||
.toEqual(`Property 'invalid' does not exist on type 'TestCmp'.`);
|
.toEqual(`Property 'invalid' does not exist on type 'TestCmp'.`);
|
||||||
});
|
});
|
||||||
|
@ -716,8 +716,8 @@ export declare class AnimationEvent {
|
||||||
|
|
||||||
const diags = env.driveDiagnostics();
|
const diags = env.driveDiagnostics();
|
||||||
expect(diags.length).toBe(2);
|
expect(diags.length).toBe(2);
|
||||||
expect(diags[0].messageText).toEqual(`Type '""' is not assignable to type 'boolean'.`);
|
expect(diags[0].messageText).toEqual(`Type 'string' is not assignable to type 'boolean'.`);
|
||||||
expect(diags[1].messageText).toEqual(`Type '"3"' is not assignable to type 'number'.`);
|
expect(diags[1].messageText).toEqual(`Type 'string' is not assignable to type 'number'.`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should produce an error for text attributes when overall strictness is enabled', () => {
|
it('should produce an error for text attributes when overall strictness is enabled', () => {
|
||||||
|
@ -725,8 +725,8 @@ export declare class AnimationEvent {
|
||||||
|
|
||||||
const diags = env.driveDiagnostics();
|
const diags = env.driveDiagnostics();
|
||||||
expect(diags.length).toBe(2);
|
expect(diags.length).toBe(2);
|
||||||
expect(diags[0].messageText).toEqual(`Type '""' is not assignable to type 'boolean'.`);
|
expect(diags[0].messageText).toEqual(`Type 'string' is not assignable to type 'boolean'.`);
|
||||||
expect(diags[1].messageText).toEqual(`Type '"3"' is not assignable to type 'number'.`);
|
expect(diags[1].messageText).toEqual(`Type 'string' is not assignable to type 'number'.`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not produce an error for text attributes when not enabled', () => {
|
it('should not produce an error for text attributes when not enabled', () => {
|
||||||
|
@ -1119,7 +1119,7 @@ export declare class AnimationEvent {
|
||||||
const allErrors = [
|
const allErrors = [
|
||||||
`'does_not_exist' does not exist on type '{ name: string; }'`,
|
`'does_not_exist' does not exist on type '{ name: string; }'`,
|
||||||
`Expected 2 arguments, but got 3.`,
|
`Expected 2 arguments, but got 3.`,
|
||||||
`Argument of type '"test"' is not assignable to parameter of type 'number'`,
|
`Argument of type 'string' is not assignable to parameter of type 'number'`,
|
||||||
`Argument of type '{ name: string; }' is not assignable to parameter of type 'unknown[]'`,
|
`Argument of type '{ name: string; }' is not assignable to parameter of type 'unknown[]'`,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -1241,11 +1241,11 @@ export declare class AnimationEvent {
|
||||||
|
|
||||||
const diags = env.driveDiagnostics();
|
const diags = env.driveDiagnostics();
|
||||||
expect(diags.length).toBe(3);
|
expect(diags.length).toBe(3);
|
||||||
expect(diags[0].messageText).toBe(`Type 'true' is not assignable to type 'number'.`);
|
expect(diags[0].messageText).toBe(`Type 'boolean' is not assignable to type 'number'.`);
|
||||||
expect(getSourceCodeForDiagnostic(diags[0])).toEqual('[fromAbstract]="true"');
|
expect(getSourceCodeForDiagnostic(diags[0])).toEqual('[fromAbstract]="true"');
|
||||||
expect(diags[1].messageText).toBe(`Type '3' is not assignable to type 'string'.`);
|
expect(diags[1].messageText).toBe(`Type 'number' is not assignable to type 'string'.`);
|
||||||
expect(getSourceCodeForDiagnostic(diags[1])).toEqual('[fromBase]="3"');
|
expect(getSourceCodeForDiagnostic(diags[1])).toEqual('[fromBase]="3"');
|
||||||
expect(diags[2].messageText).toBe(`Type '4' is not assignable to type 'boolean'.`);
|
expect(diags[2].messageText).toBe(`Type 'number' is not assignable to type 'boolean'.`);
|
||||||
expect(getSourceCodeForDiagnostic(diags[2])).toEqual('[fromChild]="4"');
|
expect(getSourceCodeForDiagnostic(diags[2])).toEqual('[fromChild]="4"');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1298,11 +1298,11 @@ export declare class AnimationEvent {
|
||||||
|
|
||||||
const diags = env.driveDiagnostics();
|
const diags = env.driveDiagnostics();
|
||||||
expect(diags.length).toBe(3);
|
expect(diags.length).toBe(3);
|
||||||
expect(diags[0].messageText).toBe(`Type 'true' is not assignable to type 'number'.`);
|
expect(diags[0].messageText).toBe(`Type 'boolean' is not assignable to type 'number'.`);
|
||||||
expect(getSourceCodeForDiagnostic(diags[0])).toEqual('[fromAbstract]="true"');
|
expect(getSourceCodeForDiagnostic(diags[0])).toEqual('[fromAbstract]="true"');
|
||||||
expect(diags[1].messageText).toBe(`Type '3' is not assignable to type 'string'.`);
|
expect(diags[1].messageText).toBe(`Type 'number' is not assignable to type 'string'.`);
|
||||||
expect(getSourceCodeForDiagnostic(diags[1])).toEqual('[fromBase]="3"');
|
expect(getSourceCodeForDiagnostic(diags[1])).toEqual('[fromBase]="3"');
|
||||||
expect(diags[2].messageText).toBe(`Type '4' is not assignable to type 'boolean'.`);
|
expect(diags[2].messageText).toBe(`Type 'number' is not assignable to type 'boolean'.`);
|
||||||
expect(getSourceCodeForDiagnostic(diags[2])).toEqual('[fromChild]="4"');
|
expect(getSourceCodeForDiagnostic(diags[2])).toEqual('[fromChild]="4"');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -584,7 +584,7 @@ describe('downlevel decorator transform', () => {
|
||||||
const visitNode = (node: ts.Node): ts.Node => {
|
const visitNode = (node: ts.Node): ts.Node => {
|
||||||
if (ts.isClassDeclaration(node) || ts.isClassElement(node)) {
|
if (ts.isClassDeclaration(node) || ts.isClassElement(node)) {
|
||||||
const cloned = ts.getMutableClone(node);
|
const cloned = ts.getMutableClone(node);
|
||||||
cloned.decorators = undefined;
|
(cloned.decorators as undefined) = undefined;
|
||||||
return cloned;
|
return cloned;
|
||||||
}
|
}
|
||||||
return ts.visitEachChild(node, visitNode, context);
|
return ts.visitEachChild(node, visitNode, context);
|
||||||
|
|
|
@ -492,11 +492,11 @@ describe('ng program', () => {
|
||||||
.toBe(true);
|
.toBe(true);
|
||||||
switch (checks.shouldBe) {
|
switch (checks.shouldBe) {
|
||||||
case ShouldBe.Empty:
|
case ShouldBe.Empty:
|
||||||
expect(writeData!.data).toMatch(/^(\s*\/\*([^*]|\*[^/])*\*\/\s*)?$/);
|
expect(writeData!.data).toMatch(/^(\s*\/\*([^*]|\*[^\/])*\*\/\s*)?$/);
|
||||||
break;
|
break;
|
||||||
case ShouldBe.EmptyExport:
|
case ShouldBe.EmptyExport:
|
||||||
expect(writeData!.data)
|
expect(writeData!.data)
|
||||||
.toMatch(/^((\s*\/\*([^*]|\*[^/])*\*\/\s*)|(\s*export\s*{\s*}\s*;\s*)|())$/);
|
.toMatch(/^((\s*\/\*([^*]|\*[^\/])*\*\/\s*)|(\s*export\s*{\s*};\s*))$/m);
|
||||||
break;
|
break;
|
||||||
case ShouldBe.NoneEmpty:
|
case ShouldBe.NoneEmpty:
|
||||||
expect(writeData!.data).not.toBe('');
|
expect(writeData!.data).not.toBe('');
|
||||||
|
@ -505,12 +505,14 @@ describe('ng program', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
assertGenFile(
|
assertGenFile(
|
||||||
'built/src/util.ngfactory.js', {originalFileName: 'src/util.ts', shouldBe: ShouldBe.Empty});
|
'built/src/util.ngfactory.js',
|
||||||
|
{originalFileName: 'src/util.ts', shouldBe: ShouldBe.EmptyExport});
|
||||||
assertGenFile(
|
assertGenFile(
|
||||||
'built/src/util.ngfactory.d.ts',
|
'built/src/util.ngfactory.d.ts',
|
||||||
{originalFileName: 'src/util.ts', shouldBe: ShouldBe.EmptyExport});
|
{originalFileName: 'src/util.ts', shouldBe: ShouldBe.EmptyExport});
|
||||||
assertGenFile(
|
assertGenFile(
|
||||||
'built/src/util.ngsummary.js', {originalFileName: 'src/util.ts', shouldBe: ShouldBe.Empty});
|
'built/src/util.ngsummary.js',
|
||||||
|
{originalFileName: 'src/util.ts', shouldBe: ShouldBe.EmptyExport});
|
||||||
assertGenFile(
|
assertGenFile(
|
||||||
'built/src/util.ngsummary.d.ts',
|
'built/src/util.ngsummary.d.ts',
|
||||||
{originalFileName: 'src/util.ts', shouldBe: ShouldBe.EmptyExport});
|
{originalFileName: 'src/util.ts', shouldBe: ShouldBe.EmptyExport});
|
||||||
|
@ -987,7 +989,8 @@ describe('ng program', () => {
|
||||||
const errorDiags =
|
const errorDiags =
|
||||||
program1.emit().diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error);
|
program1.emit().diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error);
|
||||||
expect(stripAnsi(formatDiagnostics(errorDiags)))
|
expect(stripAnsi(formatDiagnostics(errorDiags)))
|
||||||
.toContain(`src/main.ts:5:13 - error TS2322: Type '1' is not assignable to type 'string'.`);
|
.toContain(
|
||||||
|
`src/main.ts:5:13 - error TS2322: Type 'number' is not assignable to type 'string'.`);
|
||||||
expect(stripAnsi(formatDiagnostics(errorDiags)))
|
expect(stripAnsi(formatDiagnostics(errorDiags)))
|
||||||
.toContain(
|
.toContain(
|
||||||
`src/main.html:1:1 - error TS100: Property 'nonExistent' does not exist on type 'MyComp'.`);
|
`src/main.html:1:1 - error TS100: Property 'nonExistent' does not exist on type 'MyComp'.`);
|
||||||
|
|
|
@ -17,7 +17,7 @@ export function createHtmlSourceFile(filePath: string, content: string): ts.Sour
|
||||||
|
|
||||||
// Subtract two characters because the string literal quotes are only needed for parsing
|
// Subtract two characters because the string literal quotes are only needed for parsing
|
||||||
// and are not part of the actual source file.
|
// and are not part of the actual source file.
|
||||||
sourceFile.end = sourceFile.end - 2;
|
(sourceFile.end as number) = sourceFile.end - 2;
|
||||||
|
|
||||||
// Note: This does not affect the way TSLint applies replacements for external resource files.
|
// Note: This does not affect the way TSLint applies replacements for external resource files.
|
||||||
// At the time of writing, TSLint loads files manually if the actual rule source file is not
|
// At the time of writing, TSLint loads files manually if the actual rule source file is not
|
||||||
|
|
|
@ -45,8 +45,7 @@ export abstract class NgElement extends HTMLElement {
|
||||||
/**
|
/**
|
||||||
* The strategy that controls how a component is transformed in a custom element.
|
* The strategy that controls how a component is transformed in a custom element.
|
||||||
*/
|
*/
|
||||||
// TODO(issue/24571): remove '!'.
|
protected abstract ngElementStrategy: NgElementStrategy;
|
||||||
protected ngElementStrategy!: NgElementStrategy;
|
|
||||||
/**
|
/**
|
||||||
* A subscription to change, connect, and disconnect events in the custom element.
|
* A subscription to change, connect, and disconnect events in the custom element.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -849,7 +849,7 @@ function getTsTypeFromBuiltinType(builtinType: BuiltinType, ctx: TypeContext): t
|
||||||
`Internal error, unhandled literal kind ${builtinType}:${BuiltinType[builtinType]}`);
|
`Internal error, unhandled literal kind ${builtinType}:${BuiltinType[builtinType]}`);
|
||||||
}
|
}
|
||||||
const node = ts.createNode(syntaxKind);
|
const node = ts.createNode(syntaxKind);
|
||||||
node.parent = ts.createEmptyStatement();
|
(node.parent as ts.Node) = ts.createEmptyStatement();
|
||||||
return ctx.checker.getTypeAtLocation(node);
|
return ctx.checker.getTypeAtLocation(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ describe('plugin', () => {
|
||||||
const diags = plugin.getSemanticDiagnostics(fileName);
|
const diags = plugin.getSemanticDiagnostics(fileName);
|
||||||
expect(diags.length).toBe(1);
|
expect(diags.length).toBe(1);
|
||||||
expect(diags[0].messageText)
|
expect(diags[0].messageText)
|
||||||
.toBe(`Argument of type '"hello"' is not assignable to parameter of type 'number'.`);
|
.toBe(`Argument of type 'string' is not assignable to parameter of type 'number'.`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not report TypeScript errors on tour of heroes', () => {
|
it('should not report TypeScript errors on tour of heroes', () => {
|
||||||
|
|
|
@ -33,7 +33,6 @@ import {Checks, getAllRouteGuards} from './utils/preactivation';
|
||||||
import {isUrlTree} from './utils/type_guards';
|
import {isUrlTree} from './utils/type_guards';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description
|
* @description
|
||||||
*
|
*
|
||||||
|
@ -922,7 +921,7 @@ export class Router {
|
||||||
const {source, state, urlTree} = currentChange;
|
const {source, state, urlTree} = currentChange;
|
||||||
const extras: NavigationExtras = {replaceUrl: true};
|
const extras: NavigationExtras = {replaceUrl: true};
|
||||||
if (state) {
|
if (state) {
|
||||||
const stateCopy = {...state};
|
const stateCopy = {...state} as Partial<RestoredState>;
|
||||||
delete stateCopy.navigationId;
|
delete stateCopy.navigationId;
|
||||||
if (Object.keys(stateCopy).length !== 0) {
|
if (Object.keys(stateCopy).length !== 0) {
|
||||||
extras.state = stateCopy;
|
extras.state = stateCopy;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"mocha": "^3.1.2",
|
"mocha": "^3.1.2",
|
||||||
"mock-require": "3.0.3",
|
"mock-require": "3.0.3",
|
||||||
"promises-aplus-tests": "^2.1.2",
|
"promises-aplus-tests": "^2.1.2",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "4.0.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"electrontest": "cd test/extra && node electron.js",
|
"electrontest": "cd test/extra && node electron.js",
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
"chai": "^4.1.2",
|
"chai": "^4.1.2",
|
||||||
"jasmine": "^3.1.0",
|
"jasmine": "^3.1.0",
|
||||||
"source-map-support": "^0.5.9",
|
"source-map-support": "^0.5.9",
|
||||||
"typescript": "~3.9.5"
|
"typescript": "4.0.2"
|
||||||
},
|
},
|
||||||
"repository": {},
|
"repository": {},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|
|
@ -15329,10 +15329,10 @@ typescript@~3.7.2:
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
|
||||||
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
|
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
|
||||||
|
|
||||||
typescript@~3.9.5:
|
typescript@~4.0.2:
|
||||||
version "3.9.5"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2"
|
||||||
integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==
|
integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==
|
||||||
|
|
||||||
uglify-js@^1.3.3:
|
uglify-js@^1.3.3:
|
||||||
version "1.3.5"
|
version "1.3.5"
|
||||||
|
|
Loading…
Reference in New Issue