mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(core): support TypeScript 4.8 (#47038)
Adds support for TypeScript 4.8 and resolves some issues that came up as a result of the update. Most of the issues came from some changes in TypeScript where the `decorators` and `modifiers` properties were removed from most node types, and were combined into a single `modifiers` array. Since we need to continue supporting TS 4.6 and 4.7 until v15, I ended up creating a new `ngtsc/ts_compatibility` directory to make it easier to reuse the new backwards-compatible code. PR Close #47038
This commit is contained in:
committed by
Pawel Kozlowski
parent
75df404467
commit
31429eaccc
@@ -36,7 +36,7 @@
|
||||
"rollup": "^2.56.3",
|
||||
"rollup-plugin-sourcemaps": "^0.6.3",
|
||||
"terser": "^5.9.0",
|
||||
"typescript": ">=4.6.2 <4.8"
|
||||
"typescript": ">=4.6.2 <4.9"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"terser": {
|
||||
|
||||
@@ -32,6 +32,7 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/sourcemaps",
|
||||
"//packages/compiler-cli/src/ngtsc/transform",
|
||||
"//packages/compiler-cli/src/ngtsc/translator",
|
||||
"//packages/compiler-cli/src/ngtsc/ts_compatibility",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"@npm//@types/convert-source-map",
|
||||
"@npm//@types/node",
|
||||
|
||||
@@ -11,6 +11,7 @@ import ts from 'typescript';
|
||||
import {absoluteFromSourceFile} from '../../../src/ngtsc/file_system';
|
||||
import {Logger} from '../../../src/ngtsc/logging';
|
||||
import {ClassDeclaration, ClassMember, ClassMemberKind, CtorParameter, Declaration, DeclarationNode, Decorator, EnumMember, Import, isConcreteDeclaration, isDecoratorIdentifier, isNamedClassDeclaration, isNamedFunctionDeclaration, isNamedVariableDeclaration, KnownDeclaration, reflectObjectLiteral, SpecialDeclarationKind, TypeScriptReflectionHost, TypeValueReference, TypeValueReferenceKind, ValueUnavailableKind} from '../../../src/ngtsc/reflection';
|
||||
import {getModifiers} from '../../../src/ngtsc/ts_compatibility';
|
||||
import {isSymbolWithValueDeclaration, SymbolWithValueDeclaration} from '../../../src/ngtsc/util/src/typescript';
|
||||
import {isWithinPackage} from '../analysis/util';
|
||||
import {BundleProgram} from '../packages/bundle_program';
|
||||
@@ -1534,8 +1535,9 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
|
||||
// If we have still not determined if this is a static or instance member then
|
||||
// look for the `static` keyword on the declaration
|
||||
if (isStatic === undefined) {
|
||||
isStatic = node.modifiers !== undefined &&
|
||||
node.modifiers.some(mod => mod.kind === ts.SyntaxKind.StaticKeyword);
|
||||
const modifiers = getModifiers(node);
|
||||
isStatic = modifiers !== undefined &&
|
||||
modifiers.some(mod => mod.kind === ts.SyntaxKind.StaticKeyword);
|
||||
}
|
||||
|
||||
const type: ts.TypeNode = (node as any).type || null;
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/compiler": "0.0.0-PLACEHOLDER",
|
||||
"typescript": ">=4.6.2 <4.8"
|
||||
"typescript": ">=4.6.2 <4.9"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -32,6 +32,7 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/shims",
|
||||
"//packages/compiler-cli/src/ngtsc/shims:api",
|
||||
"//packages/compiler-cli/src/ngtsc/transform",
|
||||
"//packages/compiler-cli/src/ngtsc/ts_compatibility",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/api",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/diagnostics",
|
||||
|
||||
@@ -27,6 +27,7 @@ import {ComponentScopeReader, CompoundComponentScopeReader, LocalModuleScopeRegi
|
||||
import {StandaloneComponentScopeReader} from '../../scope/src/standalone';
|
||||
import {generatedFactoryTransform} from '../../shims';
|
||||
import {aliasTransformFactory, CompilationMode, declarationTransformFactory, DecoratorHandler, DtsTransformRegistry, ivyTransformFactory, TraitCompiler} from '../../transform';
|
||||
import {getModifiers} from '../../ts_compatibility';
|
||||
import {TemplateTypeCheckerImpl} from '../../typecheck';
|
||||
import {OptimizeFor, TemplateTypeChecker, TypeCheckingConfig} from '../../typecheck/api';
|
||||
import {ALL_DIAGNOSTIC_FACTORIES, ExtendedTemplateCheckerImpl} from '../../typecheck/extended';
|
||||
@@ -1107,8 +1108,9 @@ export function isAngularCorePackage(program: ts.Program): boolean {
|
||||
return false;
|
||||
}
|
||||
// It must be exported.
|
||||
if (stmt.modifiers === undefined ||
|
||||
!stmt.modifiers.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword)) {
|
||||
const modifiers = getModifiers(stmt);
|
||||
if (modifiers === undefined ||
|
||||
!modifiers.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword)) {
|
||||
return false;
|
||||
}
|
||||
// It must declare ITS_JUST_ANGULAR.
|
||||
|
||||
@@ -12,6 +12,7 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/file_system",
|
||||
"//packages/compiler-cli/src/ngtsc/imports",
|
||||
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||
"//packages/compiler-cli/src/ngtsc/ts_compatibility",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"@npm//typescript",
|
||||
],
|
||||
|
||||
@@ -10,6 +10,7 @@ import ts from 'typescript';
|
||||
|
||||
import {OwningModule, Reference} from '../../imports';
|
||||
import {ClassDeclaration, ClassMember, ClassMemberKind, isNamedClassDeclaration, ReflectionHost, reflectTypeEntityToDeclaration} from '../../reflection';
|
||||
import {getModifiers} from '../../ts_compatibility';
|
||||
import {nodeDebugInfo} from '../../util/src/typescript';
|
||||
|
||||
import {DirectiveMeta, DirectiveTypeCheckMeta, MetadataReader, NgModuleMeta, PipeMeta, TemplateGuardMeta} from './api';
|
||||
@@ -150,14 +151,12 @@ export function extractDirectiveTypeCheckMeta(
|
||||
}
|
||||
|
||||
function isRestricted(node: ts.Node): boolean {
|
||||
if (node.modifiers === undefined) {
|
||||
return false;
|
||||
}
|
||||
const modifiers = getModifiers(node);
|
||||
|
||||
return node.modifiers.some(
|
||||
modifier => modifier.kind === ts.SyntaxKind.PrivateKeyword ||
|
||||
modifier.kind === ts.SyntaxKind.ProtectedKeyword ||
|
||||
modifier.kind === ts.SyntaxKind.ReadonlyKeyword);
|
||||
return modifiers !== undefined && modifiers.some(({kind}) => {
|
||||
return kind === ts.SyntaxKind.PrivateKeyword || kind === ts.SyntaxKind.ProtectedKeyword ||
|
||||
kind === ts.SyntaxKind.ReadonlyKeyword;
|
||||
});
|
||||
}
|
||||
|
||||
function extractTemplateGuard(member: ClassMember): TemplateGuardMeta|null {
|
||||
|
||||
@@ -15,6 +15,7 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/imports",
|
||||
"//packages/compiler-cli/src/ngtsc/incremental:api",
|
||||
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||
"//packages/compiler-cli/src/ngtsc/ts_compatibility",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"@npm//@types/node",
|
||||
"@npm//typescript",
|
||||
|
||||
@@ -12,6 +12,7 @@ import {Reference} from '../../imports';
|
||||
import {OwningModule} from '../../imports/src/references';
|
||||
import {DependencyTracker} from '../../incremental/api';
|
||||
import {Declaration, DeclarationKind, DeclarationNode, EnumMember, FunctionDefinition, isConcreteDeclaration, ReflectionHost, SpecialDeclarationKind} from '../../reflection';
|
||||
import {getModifiers} from '../../ts_compatibility';
|
||||
import {isDeclaration} from '../../util/src/typescript';
|
||||
|
||||
import {ArrayConcatBuiltinFn, ArraySliceBuiltinFn, StringConcatBuiltinFn} from './builtin';
|
||||
@@ -746,8 +747,9 @@ function isVariableDeclarationDeclared(node: ts.VariableDeclaration): boolean {
|
||||
return false;
|
||||
}
|
||||
const varStmt = declList.parent;
|
||||
return varStmt.modifiers !== undefined &&
|
||||
varStmt.modifiers.some(mod => mod.kind === ts.SyntaxKind.DeclareKeyword);
|
||||
const modifiers = getModifiers(varStmt);
|
||||
return modifiers !== undefined &&
|
||||
modifiers.some(mod => mod.kind === ts.SyntaxKind.DeclareKeyword);
|
||||
}
|
||||
|
||||
const EMPTY = {};
|
||||
|
||||
@@ -7,5 +7,8 @@ ts_library(
|
||||
srcs = ["index.ts"] + glob([
|
||||
"src/**/*.ts",
|
||||
]),
|
||||
deps = ["@npm//typescript"],
|
||||
deps = [
|
||||
"//packages/compiler-cli/src/ngtsc/ts_compatibility",
|
||||
"@npm//typescript",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
import ts from 'typescript';
|
||||
|
||||
import {getDecorators, getModifiers} from '../../ts_compatibility';
|
||||
|
||||
import {ClassDeclaration, ClassMember, ClassMemberKind, CtorParameter, Declaration, DeclarationKind, DeclarationNode, Decorator, FunctionDefinition, Import, isDecoratorIdentifier, ReflectionHost} from './host';
|
||||
import {typeToValue} from './type_to_value';
|
||||
import {isNamedClassDeclaration} from './util';
|
||||
@@ -20,11 +22,12 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
||||
constructor(protected checker: ts.TypeChecker) {}
|
||||
|
||||
getDecoratorsOfDeclaration(declaration: DeclarationNode): Decorator[]|null {
|
||||
if (declaration.decorators === undefined || declaration.decorators.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return declaration.decorators.map(decorator => this._reflectDecorator(decorator))
|
||||
.filter((dec): dec is Decorator => dec !== null);
|
||||
const decorators = getDecorators(declaration);
|
||||
|
||||
return decorators !== undefined && decorators.length ?
|
||||
decorators.map(decorator => this._reflectDecorator(decorator))
|
||||
.filter((dec): dec is Decorator => dec !== null) :
|
||||
null;
|
||||
}
|
||||
|
||||
getMembersOfClass(clazz: ClassDeclaration): ClassMember[] {
|
||||
@@ -205,8 +208,9 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
||||
if (ts.isVariableDeclaration(decl) && ts.isVariableDeclarationList(decl.parent)) {
|
||||
topLevel = decl.parent.parent;
|
||||
}
|
||||
if (topLevel.modifiers !== undefined &&
|
||||
topLevel.modifiers.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
||||
const modifiers = getModifiers(topLevel);
|
||||
if (modifiers !== undefined &&
|
||||
modifiers.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
||||
// The node is part of a declaration that's directly exported.
|
||||
return true;
|
||||
}
|
||||
@@ -427,8 +431,9 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
||||
}
|
||||
|
||||
const decorators = this.getDecoratorsOfDeclaration(node);
|
||||
const isStatic = node.modifiers !== undefined &&
|
||||
node.modifiers.some(mod => mod.kind === ts.SyntaxKind.StaticKeyword);
|
||||
const modifiers = getModifiers(node);
|
||||
const isStatic =
|
||||
modifiers !== undefined && modifiers.some(mod => mod.kind === ts.SyntaxKind.StaticKeyword);
|
||||
|
||||
return {
|
||||
node,
|
||||
@@ -662,7 +667,8 @@ function getFarLeftIdentifier(propertyAccess: ts.PropertyAccessExpression): ts.I
|
||||
*/
|
||||
function getContainingImportDeclaration(node: ts.Node): ts.ImportDeclaration|null {
|
||||
return ts.isImportSpecifier(node) ? node.parent!.parent!.parent! :
|
||||
ts.isNamespaceImport(node) ? node.parent.parent : null;
|
||||
ts.isNamespaceImport(node) ? node.parent.parent :
|
||||
null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,6 +21,7 @@ ts_library(
|
||||
"//packages/compiler",
|
||||
"//packages/compiler-cli/src/ngtsc/file_system",
|
||||
"//packages/compiler-cli/src/ngtsc/imports",
|
||||
"//packages/compiler-cli/src/ngtsc/ts_compatibility",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"@npm//@types/node",
|
||||
"@npm//typescript",
|
||||
|
||||
@@ -9,6 +9,7 @@ import ts from 'typescript';
|
||||
|
||||
import {absoluteFromSourceFile, AbsoluteFsPath, basename} from '../../file_system';
|
||||
import {ImportRewriter} from '../../imports';
|
||||
import {getDecorators, getModifiers, updateImportDeclaration} from '../../ts_compatibility';
|
||||
import {FactoryInfo, FactoryTracker, ModuleInfo, PerFileShimGenerator} from '../api';
|
||||
|
||||
import {generatedModuleName} from './util';
|
||||
@@ -41,7 +42,7 @@ export class FactoryGenerator implements PerFileShimGenerator, FactoryTracker {
|
||||
.filter(ts.isClassDeclaration)
|
||||
// which are named, exported, and have decorators.
|
||||
.filter(
|
||||
decl => isExported(decl) && decl.decorators !== undefined &&
|
||||
decl => isExported(decl) && getDecorators(decl) !== undefined &&
|
||||
decl.name !== undefined)
|
||||
// Grab the symbol name.
|
||||
.map(decl => decl.name!.text);
|
||||
@@ -103,8 +104,8 @@ export class FactoryGenerator implements PerFileShimGenerator, FactoryTracker {
|
||||
}
|
||||
|
||||
function isExported(decl: ts.Declaration): boolean {
|
||||
return decl.modifiers !== undefined &&
|
||||
decl.modifiers.some(mod => mod.kind == ts.SyntaxKind.ExportKeyword);
|
||||
const modifiers = getModifiers(decl);
|
||||
return modifiers !== undefined && modifiers.some(mod => mod.kind == ts.SyntaxKind.ExportKeyword);
|
||||
}
|
||||
|
||||
export function generatedFactoryTransform(
|
||||
@@ -159,8 +160,8 @@ function transformFactorySourceFile(
|
||||
const rewrittenModuleSpecifier =
|
||||
importRewriter.rewriteSpecifier('@angular/core', sourceFilePath);
|
||||
if (rewrittenModuleSpecifier !== stmt.moduleSpecifier.text) {
|
||||
transformedStatements.push(ts.factory.updateImportDeclaration(
|
||||
stmt, stmt.decorators, stmt.modifiers, stmt.importClause,
|
||||
transformedStatements.push(updateImportDeclaration(
|
||||
stmt, getModifiers(stmt), stmt.importClause,
|
||||
ts.factory.createStringLiteral(rewrittenModuleSpecifier), undefined));
|
||||
|
||||
// Record the identifier by which this imported module goes, so references to its symbols
|
||||
@@ -316,13 +317,14 @@ function updateInitializers(
|
||||
): ts.VariableStatement {
|
||||
return ts.factory.updateVariableStatement(
|
||||
stmt,
|
||||
stmt.modifiers,
|
||||
getModifiers(stmt),
|
||||
ts.factory.updateVariableDeclarationList(
|
||||
stmt.declarationList,
|
||||
stmt.declarationList.declarations.map(
|
||||
(decl) => ts.updateVariableDeclaration(
|
||||
(decl) => ts.factory.updateVariableDeclaration(
|
||||
decl,
|
||||
decl.name,
|
||||
decl.exclamationToken,
|
||||
decl.type,
|
||||
update(decl.initializer),
|
||||
),
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import ts from 'typescript';
|
||||
|
||||
import {AbsoluteFsPath} from '../../file_system';
|
||||
import {getDecorators, getModifiers} from '../../ts_compatibility';
|
||||
import {PerFileShimGenerator} from '../api';
|
||||
|
||||
import {generatedModuleName} from './util';
|
||||
@@ -27,7 +28,7 @@ export class SummaryGenerator implements PerFileShimGenerator {
|
||||
for (const stmt of sf.statements) {
|
||||
if (ts.isClassDeclaration(stmt)) {
|
||||
// If the class isn't exported, or if it's not decorated, then skip it.
|
||||
if (!isExported(stmt) || stmt.decorators === undefined || stmt.name === undefined) {
|
||||
if (!isExported(stmt) || stmt.name === undefined || getDecorators(stmt) === undefined) {
|
||||
continue;
|
||||
}
|
||||
symbolNames.push(stmt.name.text);
|
||||
@@ -68,6 +69,8 @@ export class SummaryGenerator implements PerFileShimGenerator {
|
||||
}
|
||||
|
||||
function isExported(decl: ts.Declaration): boolean {
|
||||
return decl.modifiers !== undefined &&
|
||||
decl.modifiers.some(mod => mod.kind == ts.SyntaxKind.ExportKeyword);
|
||||
const modifiers = getModifiers(decl);
|
||||
return modifiers !== undefined &&
|
||||
modifiers.some(mod => mod.kind == ts.SyntaxKind.ExportKeyword) ||
|
||||
false;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||
"//packages/compiler-cli/src/ngtsc/shims",
|
||||
"//packages/compiler-cli/src/ngtsc/translator",
|
||||
"//packages/compiler-cli/src/ngtsc/ts_compatibility",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/api",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/extended/api",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
|
||||
@@ -12,6 +12,7 @@ import ts from 'typescript';
|
||||
import {ImportRewriter} from '../../imports';
|
||||
import {ClassDeclaration} from '../../reflection';
|
||||
import {ImportManager, translateType} from '../../translator';
|
||||
import {createPropertyDeclaration, updateClassDeclaration} from '../../ts_compatibility';
|
||||
|
||||
import {DtsTransform} from './api';
|
||||
import {addImports} from './utils';
|
||||
@@ -140,9 +141,8 @@ class DtsTransformer {
|
||||
// If some elements have been transformed but the class itself has not been transformed, create
|
||||
// an updated class declaration with the updated elements.
|
||||
if (elementsChanged && clazz === newClazz) {
|
||||
newClazz = ts.factory.updateClassDeclaration(
|
||||
newClazz = updateClassDeclaration(
|
||||
/* node */ clazz,
|
||||
/* decorators */ clazz.decorators,
|
||||
/* modifiers */ clazz.modifiers,
|
||||
/* name */ clazz.name,
|
||||
/* typeParameters */ clazz.typeParameters,
|
||||
@@ -194,8 +194,7 @@ export class IvyDeclarationDtsTransform implements DtsTransform {
|
||||
const modifiers = [ts.factory.createModifier(ts.SyntaxKind.StaticKeyword)];
|
||||
const typeRef = translateType(decl.type, imports);
|
||||
markForEmitAsSingleLine(typeRef);
|
||||
return ts.factory.createPropertyDeclaration(
|
||||
/* decorators */ undefined,
|
||||
return createPropertyDeclaration(
|
||||
/* modifiers */ modifiers,
|
||||
/* name */ decl.name,
|
||||
/* questionOrExclamationToken */ undefined,
|
||||
@@ -203,9 +202,8 @@ export class IvyDeclarationDtsTransform implements DtsTransform {
|
||||
/* initializer */ undefined);
|
||||
});
|
||||
|
||||
return ts.factory.updateClassDeclaration(
|
||||
return updateClassDeclaration(
|
||||
/* node */ clazz,
|
||||
/* decorators */ clazz.decorators,
|
||||
/* modifiers */ clazz.modifiers,
|
||||
/* name */ clazz.name,
|
||||
/* typeParameters */ clazz.typeParameters,
|
||||
|
||||
@@ -14,6 +14,7 @@ import {getDefaultImportDeclaration} from '../../imports/src/default';
|
||||
import {PerfPhase, PerfRecorder} from '../../perf';
|
||||
import {Decorator, ReflectionHost} from '../../reflection';
|
||||
import {ImportManager, RecordWrappedNodeFn, translateExpression, translateStatement, TranslatorOptions} from '../../translator';
|
||||
import {combineModifiers, createPropertyDeclaration, getDecorators, getModifiers, updateClassDeclaration, updateConstructorDeclaration, updateGetAccessorDeclaration, updateMethodDeclaration, updateParameterDeclaration, updatePropertyDeclaration, updateSetAccessorDeclaration} from '../../ts_compatibility';
|
||||
import {visit, VisitListEntryResult, Visitor} from '../../util/src/visitor';
|
||||
|
||||
import {CompileResult} from './api';
|
||||
@@ -109,9 +110,9 @@ class IvyTransformationVisitor extends Visitor {
|
||||
const exprNode = translateExpression(field.initializer, this.importManager, translateOptions);
|
||||
|
||||
// Create a static property declaration for the new field.
|
||||
const property = ts.factory.createPropertyDeclaration(
|
||||
undefined, [ts.factory.createToken(ts.SyntaxKind.StaticKeyword)], field.name, undefined,
|
||||
undefined, exprNode);
|
||||
const property = createPropertyDeclaration(
|
||||
[ts.factory.createToken(ts.SyntaxKind.StaticKeyword)], field.name, undefined, undefined,
|
||||
exprNode);
|
||||
|
||||
if (this.isClosureCompilerEnabled) {
|
||||
// Closure compiler transforms the form `Service.ɵprov = X` into `Service$ɵprov = X`. To
|
||||
@@ -129,12 +130,14 @@ class IvyTransformationVisitor extends Visitor {
|
||||
members.push(property);
|
||||
}
|
||||
|
||||
// Replace the class declaration with an updated version.
|
||||
node = ts.factory.updateClassDeclaration(
|
||||
node,
|
||||
const filteredDecorators =
|
||||
// Remove the decorator which triggered this compilation, leaving the others alone.
|
||||
maybeFilterDecorator(node.decorators, this.compilation.decoratorsFor(node)), node.modifiers,
|
||||
node.name, node.typeParameters, node.heritageClauses || [],
|
||||
maybeFilterDecorator(getDecorators(node), this.compilation.decoratorsFor(node));
|
||||
|
||||
// Replace the class declaration with an updated version.
|
||||
node = updateClassDeclaration(
|
||||
node, combineModifiers(filteredDecorators, getModifiers(node)), node.name,
|
||||
node.typeParameters, node.heritageClauses || [],
|
||||
// Map over the class members and remove any Angular decorators from them.
|
||||
members.map(member => this._stripAngularDecorators(member)));
|
||||
return {node, after: statements};
|
||||
@@ -158,31 +161,26 @@ class IvyTransformationVisitor extends Visitor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a `ts.Node`, filter the decorators array and return a version containing only non-Angular
|
||||
* decorators.
|
||||
*
|
||||
* If all decorators are removed (or none existed in the first place), this method returns
|
||||
* `undefined`.
|
||||
*/
|
||||
private _nonCoreDecoratorsOnly(node: ts.Declaration): ts.NodeArray<ts.Decorator>|undefined {
|
||||
const decorators = getDecorators(node);
|
||||
|
||||
// Shortcut if the node has no decorators.
|
||||
if (node.decorators === undefined) {
|
||||
if (decorators === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
// Build a Set of the decorators on this node from @angular/core.
|
||||
const coreDecorators = this._angularCoreDecorators(node);
|
||||
|
||||
if (coreDecorators.size === node.decorators.length) {
|
||||
if (coreDecorators.size === decorators.length) {
|
||||
// If all decorators are to be removed, return `undefined`.
|
||||
return undefined;
|
||||
} else if (coreDecorators.size === 0) {
|
||||
// If no decorators need to be removed, return the original decorators array.
|
||||
return node.decorators;
|
||||
return nodeArrayFromDecoratorsArray(decorators);
|
||||
}
|
||||
|
||||
// Filter out the core decorators.
|
||||
const filtered = node.decorators.filter(dec => !coreDecorators.has(dec));
|
||||
const filtered = decorators.filter(dec => !coreDecorators.has(dec));
|
||||
|
||||
// If no decorators survive, return `undefined`. This can only happen if a core decorator is
|
||||
// repeated on the node.
|
||||
@@ -191,10 +189,7 @@ class IvyTransformationVisitor extends Visitor {
|
||||
}
|
||||
|
||||
// Create a new `NodeArray` with the filtered decorators that sourcemaps back to the original.
|
||||
const array = ts.factory.createNodeArray(filtered);
|
||||
(array.pos as number) = node.decorators.pos;
|
||||
(array.end as number) = node.decorators.end;
|
||||
return array;
|
||||
return nodeArrayFromDecoratorsArray(filtered);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,40 +201,40 @@ class IvyTransformationVisitor extends Visitor {
|
||||
private _stripAngularDecorators<T extends ts.Node>(node: T): T {
|
||||
if (ts.isParameter(node)) {
|
||||
// Strip decorators from parameters (probably of the constructor).
|
||||
node = ts.factory.updateParameterDeclaration(
|
||||
node, this._nonCoreDecoratorsOnly(node), node.modifiers, node.dotDotDotToken,
|
||||
node.name, node.questionToken, node.type, node.initializer) as T &
|
||||
node = updateParameterDeclaration(
|
||||
node, combineModifiers(this._nonCoreDecoratorsOnly(node), getModifiers(node)),
|
||||
node.dotDotDotToken, node.name, node.questionToken, node.type, node.initializer) as
|
||||
T &
|
||||
ts.ParameterDeclaration;
|
||||
} else if (ts.isMethodDeclaration(node) && node.decorators !== undefined) {
|
||||
} else if (ts.isMethodDeclaration(node) && getDecorators(node) !== undefined) {
|
||||
// Strip decorators of methods.
|
||||
node = ts.factory.updateMethodDeclaration(
|
||||
node, this._nonCoreDecoratorsOnly(node), node.modifiers, node.asteriskToken,
|
||||
node.name, node.questionToken, node.typeParameters, node.parameters, node.type,
|
||||
node.body) as T &
|
||||
node = updateMethodDeclaration(
|
||||
node, combineModifiers(this._nonCoreDecoratorsOnly(node), getModifiers(node)),
|
||||
node.asteriskToken, node.name, node.questionToken, node.typeParameters,
|
||||
node.parameters, node.type, node.body) as T &
|
||||
ts.MethodDeclaration;
|
||||
} else if (ts.isPropertyDeclaration(node) && node.decorators !== undefined) {
|
||||
} else if (ts.isPropertyDeclaration(node) && getDecorators(node) !== undefined) {
|
||||
// Strip decorators of properties.
|
||||
node = ts.factory.updatePropertyDeclaration(
|
||||
node, this._nonCoreDecoratorsOnly(node), node.modifiers, node.name,
|
||||
node.questionToken, node.type, node.initializer) as T &
|
||||
node = updatePropertyDeclaration(
|
||||
node, combineModifiers(this._nonCoreDecoratorsOnly(node), getModifiers(node)),
|
||||
node.name, node.questionToken, node.type, node.initializer) as T &
|
||||
ts.PropertyDeclaration;
|
||||
} else if (ts.isGetAccessor(node)) {
|
||||
// Strip decorators of getters.
|
||||
node = ts.factory.updateGetAccessorDeclaration(
|
||||
node, this._nonCoreDecoratorsOnly(node), node.modifiers, node.name,
|
||||
node.parameters, node.type, node.body) as T &
|
||||
node = updateGetAccessorDeclaration(
|
||||
node, combineModifiers(this._nonCoreDecoratorsOnly(node), getModifiers(node)),
|
||||
node.name, node.parameters, node.type, node.body) as T &
|
||||
ts.GetAccessorDeclaration;
|
||||
} else if (ts.isSetAccessor(node)) {
|
||||
// Strip decorators of setters.
|
||||
node = ts.factory.updateSetAccessorDeclaration(
|
||||
node, this._nonCoreDecoratorsOnly(node), node.modifiers, node.name,
|
||||
node.parameters, node.body) as T &
|
||||
node = updateSetAccessorDeclaration(
|
||||
node, combineModifiers(this._nonCoreDecoratorsOnly(node), getModifiers(node)),
|
||||
node.name, node.parameters, node.body) as T &
|
||||
ts.SetAccessorDeclaration;
|
||||
} else if (ts.isConstructorDeclaration(node)) {
|
||||
// For constructors, strip decorators of the parameters.
|
||||
const parameters = node.parameters.map(param => this._stripAngularDecorators(param));
|
||||
node = ts.factory.updateConstructorDeclaration(
|
||||
node, node.decorators, node.modifiers, parameters, node.body) as T &
|
||||
node = updateConstructorDeclaration(node, getModifiers(node), parameters, node.body) as T &
|
||||
ts.ConstructorDeclaration;
|
||||
}
|
||||
return node;
|
||||
@@ -354,7 +349,7 @@ function setFileOverviewComment(sf: ts.SourceFile, fileoverview: FileOverviewMet
|
||||
}
|
||||
|
||||
function maybeFilterDecorator(
|
||||
decorators: ts.NodeArray<ts.Decorator>|undefined,
|
||||
decorators: readonly ts.Decorator[]|undefined,
|
||||
toRemove: ts.Decorator[]): ts.NodeArray<ts.Decorator>|undefined {
|
||||
if (decorators === undefined) {
|
||||
return undefined;
|
||||
@@ -380,3 +375,16 @@ function createRecorderFn(defaultImportTracker: DefaultImportTracker):
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Creates a `NodeArray` with the correct offsets from an array of decorators. */
|
||||
function nodeArrayFromDecoratorsArray(decorators: readonly ts.Decorator[]):
|
||||
ts.NodeArray<ts.Decorator> {
|
||||
const array = ts.factory.createNodeArray(decorators);
|
||||
|
||||
if (array.length > 0) {
|
||||
(array.pos as number) = decorators[0].pos;
|
||||
(array.end as number) = decorators[decorators.length - 1].end;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
load("//tools:defaults.bzl", "ts_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ts_library(
|
||||
name = "ts_compatibility",
|
||||
srcs = ["index.ts"] + glob([
|
||||
"src/**/*.ts",
|
||||
]),
|
||||
deps = ["@npm//typescript"],
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
export * from './src/ts_cross_version_utils';
|
||||
@@ -0,0 +1,296 @@
|
||||
/*!
|
||||
* @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 ts from 'typescript';
|
||||
|
||||
/** Whether the current TypeScript version is after 4.8. */
|
||||
export const IS_AFTER_TS_48 = isAfterVersion(4, 8);
|
||||
|
||||
/** Whether the current TypeScript version is after 4.7. */
|
||||
const IS_AFTER_TS_47 = isAfterVersion(4, 7);
|
||||
|
||||
/** Equivalent of `ts.ModifierLike` which is only present in TS 4.8+. */
|
||||
export type ModifierLike = ts.Modifier|ts.Decorator;
|
||||
|
||||
/** Type of `ts.factory.updateTypeParameterDeclaration` in TS 4.7+. */
|
||||
type Ts47UpdateTypeParameterDeclarationFn =
|
||||
(node: ts.TypeParameterDeclaration, modifiers: readonly ts.Modifier[]|undefined,
|
||||
name: ts.Identifier, constraint: ts.TypeNode|undefined, defaultType: ts.TypeNode|undefined) =>
|
||||
ts.TypeParameterDeclaration;
|
||||
|
||||
/**
|
||||
* Updates a `ts.TypeParameter` declaration.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.7.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const updateTypeParameterDeclaration: Ts47UpdateTypeParameterDeclarationFn = IS_AFTER_TS_47 ?
|
||||
(ts.factory.updateTypeParameterDeclaration as any) :
|
||||
(node, _modifiers, name, constraint, defaultType) =>
|
||||
(ts.factory.updateTypeParameterDeclaration as any)(node, name, constraint, defaultType);
|
||||
|
||||
/** Type of `ts.factory.updateParameterDeclaration` in TS 4.8+. */
|
||||
type Ts48UpdateParameterDeclarationFn =
|
||||
(node: ts.ParameterDeclaration, modifiers: readonly ModifierLike[]|undefined,
|
||||
dotDotDotToken: ts.DotDotDotToken|undefined, name: string|ts.BindingName,
|
||||
questionToken: ts.QuestionToken|undefined, type: ts.TypeNode|undefined,
|
||||
initializer: ts.Expression|undefined) => ts.ParameterDeclaration;
|
||||
|
||||
/**
|
||||
* Updates a `ts.ParameterDeclaration` declaration.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const updateParameterDeclaration: Ts48UpdateParameterDeclarationFn = IS_AFTER_TS_48 ?
|
||||
(ts.factory.updateParameterDeclaration as any) :
|
||||
(node, modifiers, dotDotDotToken, name, questionToken, type, initializer) => (
|
||||
ts.factory.updateParameterDeclaration as any)(
|
||||
node, ...splitModifiers(modifiers), dotDotDotToken, name, questionToken, type, initializer);
|
||||
|
||||
/** Type of `ts.factory.updateImportDeclaration` in TS 4.8+. */
|
||||
type Ts48UpdateImportDeclarationFn =
|
||||
(node: ts.ImportDeclaration, modifiers: readonly ts.Modifier[]|undefined,
|
||||
importClause: ts.ImportClause|undefined, moduleSpecifier: ts.Expression,
|
||||
assertClause: ts.AssertClause|undefined) => ts.ImportDeclaration;
|
||||
|
||||
/**
|
||||
* Updates a `ts.ImportDeclaration` declaration.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const updateImportDeclaration: Ts48UpdateImportDeclarationFn = IS_AFTER_TS_48 ?
|
||||
(ts.factory.updateImportDeclaration as any) :
|
||||
(node, modifiers, importClause, moduleSpecifier, assertClause) =>
|
||||
(ts.factory.updateImportDeclaration as any)(
|
||||
node, undefined, modifiers, importClause, moduleSpecifier, assertClause);
|
||||
|
||||
/** Type of `ts.factory.updateClassDeclaration` in TS 4.8+. */
|
||||
type Ts48UpdateClassDeclarationFn =
|
||||
(node: ts.ClassDeclaration, modifiers: readonly ModifierLike[]|undefined,
|
||||
name: ts.Identifier|undefined,
|
||||
typeParameters: readonly ts.TypeParameterDeclaration[]|undefined,
|
||||
heritageClauses: readonly ts.HeritageClause[]|undefined,
|
||||
members: readonly ts.ClassElement[]) => ts.ClassDeclaration;
|
||||
|
||||
/**
|
||||
* Updates a `ts.ClassDeclaration` declaration.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const updateClassDeclaration: Ts48UpdateClassDeclarationFn = IS_AFTER_TS_48 ?
|
||||
(ts.factory.updateClassDeclaration as any) :
|
||||
(node, combinedModifiers, name, typeParameters, heritageClauses, members) => (
|
||||
ts.factory.updateClassDeclaration as any)(
|
||||
node, ...splitModifiers(combinedModifiers), name, typeParameters, heritageClauses, members);
|
||||
|
||||
|
||||
/** Type of `ts.factory.updateMethodDeclaration` in TS 4.8+. */
|
||||
type Ts48UpdateMethodDeclarationFn =
|
||||
(node: ts.MethodDeclaration, modifiers: readonly ModifierLike[]|undefined,
|
||||
asteriskToken: ts.AsteriskToken|undefined, name: ts.PropertyName,
|
||||
questionToken: ts.QuestionToken|undefined,
|
||||
typeParameters: readonly ts.TypeParameterDeclaration[]|undefined,
|
||||
parameters: readonly ts.ParameterDeclaration[], type: ts.TypeNode|undefined,
|
||||
body: ts.Block|undefined) => ts.MethodDeclaration;
|
||||
|
||||
/**
|
||||
* Updates a `ts.MethodDeclaration` declaration.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const updateMethodDeclaration: Ts48UpdateMethodDeclarationFn = IS_AFTER_TS_48 ?
|
||||
(ts.factory.updateMethodDeclaration as any) :
|
||||
(node, modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body) =>
|
||||
(ts.factory.updateMethodDeclaration as any)(
|
||||
node, ...splitModifiers(modifiers), asteriskToken, name, questionToken, typeParameters,
|
||||
parameters, type, body);
|
||||
|
||||
|
||||
/** Type of `ts.factory.updatePropertyDeclaration` in TS 4.8+. */
|
||||
type Ts48UpdatePropertyDeclarationFn =
|
||||
(node: ts.PropertyDeclaration, modifiers: readonly ModifierLike[]|undefined,
|
||||
name: string|ts.PropertyName,
|
||||
questionOrExclamationToken: ts.QuestionToken|ts.ExclamationToken|undefined,
|
||||
type: ts.TypeNode|undefined, initializer: ts.Expression|undefined) => ts.PropertyDeclaration;
|
||||
|
||||
/**
|
||||
* Updates a `ts.PropertyDeclaration` declaration.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const updatePropertyDeclaration: Ts48UpdatePropertyDeclarationFn = IS_AFTER_TS_48 ?
|
||||
(ts.factory.updatePropertyDeclaration as any) :
|
||||
(node, modifiers, name, questionOrExclamationToken, type, initializer) => (
|
||||
ts.factory.updatePropertyDeclaration as any)(
|
||||
node, ...splitModifiers(modifiers), name, questionOrExclamationToken, type, initializer);
|
||||
|
||||
|
||||
/** Type of `ts.factory.createPropertyDeclaration` in TS 4.8+. */
|
||||
type Ts48CreatePropertyDeclarationFn =
|
||||
(modifiers: readonly ModifierLike[]|undefined, name: string|ts.PropertyName,
|
||||
questionOrExclamationToken: ts.QuestionToken|ts.ExclamationToken|undefined,
|
||||
type: ts.TypeNode|undefined, initializer: ts.Expression|undefined) => ts.PropertyDeclaration;
|
||||
|
||||
/**
|
||||
* Creates a `ts.PropertyDeclaration` declaration.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const createPropertyDeclaration: Ts48CreatePropertyDeclarationFn = IS_AFTER_TS_48 ?
|
||||
(ts.factory.createPropertyDeclaration as any) :
|
||||
(modifiers, name, questionOrExclamationToken, type, initializer) =>
|
||||
(ts.factory.createPropertyDeclaration as any)(
|
||||
...splitModifiers(modifiers), name, questionOrExclamationToken, type, initializer);
|
||||
|
||||
|
||||
|
||||
/** Type of `ts.factory.updateGetAccessorDeclaration` in TS 4.8+. */
|
||||
type Ts48UpdateGetAccessorDeclarationFn =
|
||||
(node: ts.GetAccessorDeclaration, modifiers: readonly ModifierLike[]|undefined,
|
||||
name: ts.PropertyName, parameters: readonly ts.ParameterDeclaration[],
|
||||
type: ts.TypeNode|undefined, body: ts.Block|undefined) => ts.GetAccessorDeclaration;
|
||||
|
||||
|
||||
/**
|
||||
* Updates a `ts.GetAccessorDeclaration` declaration.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const updateGetAccessorDeclaration: Ts48UpdateGetAccessorDeclarationFn = IS_AFTER_TS_48 ?
|
||||
(ts.factory.updateGetAccessorDeclaration as any) :
|
||||
(node, modifiers, name, parameters, type, body) =>
|
||||
(ts.factory.updateGetAccessorDeclaration as any)(
|
||||
node, ...splitModifiers(modifiers), name, parameters, type, body);
|
||||
|
||||
/** Type of `ts.factory.updateSetAccessorDeclaration` in TS 4.8+. */
|
||||
type Ts48UpdateSetAccessorDeclarationFn =
|
||||
(node: ts.SetAccessorDeclaration, modifiers: readonly ModifierLike[]|undefined,
|
||||
name: ts.PropertyName, parameters: readonly ts.ParameterDeclaration[],
|
||||
body: ts.Block|undefined) => ts.SetAccessorDeclaration;
|
||||
|
||||
/**
|
||||
* Updates a `ts.GetAccessorDeclaration` declaration.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const updateSetAccessorDeclaration: Ts48UpdateSetAccessorDeclarationFn = IS_AFTER_TS_48 ?
|
||||
(ts.factory.updateSetAccessorDeclaration as any) :
|
||||
(node, modifiers, name, parameters, body) => (ts.factory.updateSetAccessorDeclaration as any)(
|
||||
node, ...splitModifiers(modifiers), name, parameters, body);
|
||||
|
||||
|
||||
|
||||
/** Type of `ts.factory.updateConstructorDeclaration` in TS 4.8+. */
|
||||
type Ts48UpdateConstructorDeclarationFn =
|
||||
(node: ts.ConstructorDeclaration, modifiers: readonly ts.Modifier[]|undefined,
|
||||
parameters: readonly ts.ParameterDeclaration[], body: ts.Block|undefined) =>
|
||||
ts.ConstructorDeclaration;
|
||||
|
||||
/**
|
||||
* Updates a `ts.ConstructorDeclaration` declaration.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const updateConstructorDeclaration: Ts48UpdateConstructorDeclarationFn = IS_AFTER_TS_48 ?
|
||||
(ts.factory.updateConstructorDeclaration as any) :
|
||||
(node, modifiers, parameters, body) => (ts.factory.updateConstructorDeclaration as any)(
|
||||
node, undefined, modifiers, parameters, body);
|
||||
|
||||
/**
|
||||
* Gets the decorators that have been applied to a node.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const getDecorators: (node: ts.Node) => readonly ts.Decorator[] | undefined =
|
||||
IS_AFTER_TS_48 ? (ts as any).getDecorators : node => node.decorators;
|
||||
|
||||
/**
|
||||
* Gets the modifiers that have been set on a node.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export const getModifiers: (node: ts.Node) => readonly ts.Modifier[] | undefined =
|
||||
IS_AFTER_TS_48 ? (ts as any).getModifiers : node => node.modifiers;
|
||||
|
||||
/**
|
||||
* Combines an optional array of decorators with an optional array of modifiers into a single
|
||||
* `ts.ModifierLike` array. Used in version of TypeScript after 4.8 where the `decorators` and
|
||||
* `modifiers` arrays have been combined.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.8.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export function combineModifiers(
|
||||
decorators: readonly ts.Decorator[]|undefined,
|
||||
modifiers: readonly ModifierLike[]|undefined): readonly ModifierLike[]|undefined {
|
||||
const hasDecorators = decorators?.length;
|
||||
const hasModifiers = modifiers?.length;
|
||||
|
||||
// This function can be written more compactly, but it is somewhat performance-sensitive
|
||||
// so we have some additional logic only to create new arrays when necessary.
|
||||
if (hasDecorators && hasModifiers) {
|
||||
return [...decorators, ...modifiers];
|
||||
}
|
||||
|
||||
if (hasDecorators && !hasModifiers) {
|
||||
return decorators;
|
||||
}
|
||||
|
||||
if (hasModifiers && !hasDecorators) {
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits a `ModifierLike` into two arrays: decorators and modifiers. Used for backwards
|
||||
* compatibility with TS 4.7 and below where most factory functions require separate `decorators`
|
||||
* and `modifiers` arrays.
|
||||
*/
|
||||
function splitModifiers(allModifiers: readonly ModifierLike[]|
|
||||
undefined): [ts.Decorator[]|undefined, ts.Modifier[]|undefined] {
|
||||
if (!allModifiers) {
|
||||
return [undefined, undefined];
|
||||
}
|
||||
|
||||
const decorators: ts.Decorator[] = [];
|
||||
const modifiers: ts.Modifier[] = [];
|
||||
|
||||
for (const current of allModifiers) {
|
||||
if (ts.isDecorator(current)) {
|
||||
decorators.push(current);
|
||||
} else {
|
||||
modifiers.push(current);
|
||||
}
|
||||
}
|
||||
|
||||
return [decorators.length ? decorators : undefined, modifiers.length ? modifiers : undefined];
|
||||
}
|
||||
|
||||
/** Checks if the current version of TypeScript is after the specified major/minor versions. */
|
||||
function isAfterVersion(targetMajor: number, targetMinor: number): boolean {
|
||||
const [major, minor] = ts.versionMajorMinor.split('.').map(part => parseInt(part));
|
||||
|
||||
if (major < targetMajor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return major === targetMajor ? minor >= targetMinor : true;
|
||||
}
|
||||
@@ -22,6 +22,7 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/shims",
|
||||
"//packages/compiler-cli/src/ngtsc/shims:api",
|
||||
"//packages/compiler-cli/src/ngtsc/translator",
|
||||
"//packages/compiler-cli/src/ngtsc/ts_compatibility",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/api",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
import ts from 'typescript';
|
||||
|
||||
const PARSED_TS_VERSION = parseFloat(ts.versionMajorMinor);
|
||||
|
||||
|
||||
/**
|
||||
* A `Set` of `ts.SyntaxKind`s of `ts.Expression` which are safe to wrap in a `ts.AsExpression`
|
||||
@@ -134,21 +132,6 @@ export function tsCallMethod(
|
||||
/* argumentsArray */ args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a `ts.TypeParameter` declaration.
|
||||
*
|
||||
* TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.7.
|
||||
* We should remove it once we have dropped support for the older versions.
|
||||
*/
|
||||
export function tsUpdateTypeParameterDeclaration(
|
||||
node: ts.TypeParameterDeclaration, name: ts.Identifier, constraint: ts.TypeNode|undefined,
|
||||
defaultType: ts.TypeNode|undefined): ts.TypeParameterDeclaration {
|
||||
return PARSED_TS_VERSION < 4.7 ?
|
||||
ts.factory.updateTypeParameterDeclaration(node, name, constraint, defaultType) :
|
||||
(ts.factory.updateTypeParameterDeclaration as any)(
|
||||
node, /* modifiers */[], name, constraint, defaultType);
|
||||
}
|
||||
|
||||
export function isAccessExpression(node: ts.Node): node is ts.ElementAccessExpression|
|
||||
ts.PropertyAccessExpression {
|
||||
return ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node);
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
import ts from 'typescript';
|
||||
|
||||
import {ClassDeclaration, ReflectionHost} from '../../reflection';
|
||||
import {updateTypeParameterDeclaration} from '../../ts_compatibility';
|
||||
import {TypeCtorMetadata} from '../api';
|
||||
|
||||
import {checkIfGenericTypeBoundsCanBeEmitted, ReferenceEmitEnvironment} from './tcb_util';
|
||||
import {tsCreateTypeQueryForCoercedInput, tsUpdateTypeParameterDeclaration} from './ts_util';
|
||||
import {tsCreateTypeQueryForCoercedInput} from './ts_util';
|
||||
|
||||
export function generateTypeCtorDeclarationFn(
|
||||
node: ClassDeclaration<ts.ClassDeclaration>, meta: TypeCtorMetadata, nodeTypeRef: ts.EntityName,
|
||||
@@ -244,8 +245,8 @@ function typeParametersWithDefaultTypes(params: ReadonlyArray<ts.TypeParameterDe
|
||||
|
||||
return params.map(param => {
|
||||
if (param.default === undefined) {
|
||||
return tsUpdateTypeParameterDeclaration(
|
||||
param, param.name, param.constraint,
|
||||
return updateTypeParameterDeclaration(
|
||||
param, param.modifiers, param.name, param.constraint,
|
||||
ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword));
|
||||
} else {
|
||||
return param;
|
||||
|
||||
@@ -9,8 +9,8 @@ import ts from 'typescript';
|
||||
|
||||
import {OwningModule, Reference} from '../../imports';
|
||||
import {DeclarationNode, ReflectionHost} from '../../reflection';
|
||||
import {updateTypeParameterDeclaration} from '../../ts_compatibility';
|
||||
|
||||
import {tsUpdateTypeParameterDeclaration} from './ts_util';
|
||||
import {canEmitType, TypeEmitter} from './type_emitter';
|
||||
|
||||
|
||||
@@ -74,7 +74,8 @@ export class TypeParameterEmitter {
|
||||
const defaultType =
|
||||
typeParam.default !== undefined ? emitter.emitType(typeParam.default) : undefined;
|
||||
|
||||
return tsUpdateTypeParameterDeclaration(typeParam, typeParam.name, constraint, defaultType);
|
||||
return updateTypeParameterDeclaration(
|
||||
typeParam, typeParam.modifiers, typeParam.name, constraint, defaultType);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/file_system",
|
||||
"//packages/compiler-cli/src/ngtsc/incremental:api",
|
||||
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||
"//packages/compiler-cli/src/ngtsc/ts_compatibility",
|
||||
"@npm//@types/node",
|
||||
"@npm//typescript",
|
||||
],
|
||||
|
||||
@@ -12,6 +12,7 @@ const D_TS = /\.d\.ts$/i;
|
||||
import ts from 'typescript';
|
||||
import {AbsoluteFsPath, getFileSystem} from '../../file_system';
|
||||
import {DeclarationNode} from '../../reflection';
|
||||
import {getModifiers} from '../../ts_compatibility';
|
||||
|
||||
/**
|
||||
* Type describing a symbol that is guaranteed to have a value declaration.
|
||||
@@ -110,8 +111,9 @@ export function isExported(node: DeclarationNode): boolean {
|
||||
if (ts.isVariableDeclaration(node) && ts.isVariableDeclarationList(node.parent)) {
|
||||
topLevel = node.parent.parent;
|
||||
}
|
||||
return topLevel.modifiers !== undefined &&
|
||||
topLevel.modifiers.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword);
|
||||
const modifiers = getModifiers(topLevel);
|
||||
return modifiers !== undefined &&
|
||||
modifiers.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword);
|
||||
}
|
||||
|
||||
export function getRootDirs(
|
||||
|
||||
@@ -13,6 +13,7 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/file_system",
|
||||
"//packages/compiler-cli/src/ngtsc/file_system/testing",
|
||||
"//packages/compiler-cli/src/ngtsc/testing",
|
||||
"//packages/compiler-cli/src/ngtsc/ts_compatibility",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"@npm//typescript",
|
||||
],
|
||||
|
||||
@@ -10,6 +10,7 @@ import ts from 'typescript';
|
||||
import {absoluteFrom, getSourceFileOrError} from '../../file_system';
|
||||
import {runInEachFileSystem} from '../../file_system/testing';
|
||||
import {makeProgram} from '../../testing';
|
||||
import {getModifiers} from '../../ts_compatibility';
|
||||
import {visit, VisitListEntryResult, Visitor} from '../src/visitor';
|
||||
|
||||
class TestAstVisitor extends Visitor {
|
||||
@@ -17,8 +18,8 @@ class TestAstVisitor extends Visitor {
|
||||
VisitListEntryResult<ts.Statement, ts.ClassDeclaration> {
|
||||
const name = node.name!.text;
|
||||
const statics = node.members.filter(
|
||||
member => (member.modifiers as ReadonlyArray<ts.Modifier>||
|
||||
[]).some(mod => mod.kind === ts.SyntaxKind.StaticKeyword));
|
||||
member =>
|
||||
(getModifiers(member) || []).some(mod => mod.kind === ts.SyntaxKind.StaticKeyword));
|
||||
const idStatic = statics.find(
|
||||
el => ts.isPropertyDeclaration(el) && ts.isIdentifier(el.name) &&
|
||||
el.name.text === 'id') as ts.PropertyDeclaration |
|
||||
|
||||
@@ -7,6 +7,7 @@ ts_library(
|
||||
srcs = glob(["*.ts"]),
|
||||
deps = [
|
||||
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||
"//packages/compiler-cli/src/ngtsc/ts_compatibility",
|
||||
"@npm//typescript",
|
||||
],
|
||||
)
|
||||
|
||||
+36
-21
@@ -9,6 +9,7 @@
|
||||
import ts from 'typescript';
|
||||
|
||||
import {Decorator, ReflectionHost} from '../../ngtsc/reflection';
|
||||
import {combineModifiers, createPropertyDeclaration, getDecorators, getModifiers, IS_AFTER_TS_48, updateClassDeclaration, updateConstructorDeclaration, updateParameterDeclaration} from '../../ngtsc/ts_compatibility';
|
||||
|
||||
import {isAliasImportDeclaration, loadIsReferencedAliasDeclarationPatch} from './patch_alias_reference_resolution';
|
||||
|
||||
@@ -136,9 +137,9 @@ function createCtorParametersClassProperty(
|
||||
undefined, undefined, [], undefined,
|
||||
ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
|
||||
ts.factory.createArrayLiteralExpression(params, true));
|
||||
const ctorProp = ts.factory.createPropertyDeclaration(
|
||||
undefined, [ts.factory.createToken(ts.SyntaxKind.StaticKeyword)], 'ctorParameters', undefined,
|
||||
undefined, initializer);
|
||||
const ctorProp = createPropertyDeclaration(
|
||||
[ts.factory.createToken(ts.SyntaxKind.StaticKeyword)], 'ctorParameters', undefined, undefined,
|
||||
initializer);
|
||||
if (isClosureCompilerEnabled) {
|
||||
ts.setSyntheticLeadingComments(ctorProp, [
|
||||
{
|
||||
@@ -290,8 +291,8 @@ export function getDownlevelDecoratorsTransform(
|
||||
// case previously, and adding it back in leads to substantial code size
|
||||
// increases as Closure fails to tree shake these props
|
||||
// without @nocollapse.
|
||||
const prop = ts.factory.createPropertyDeclaration(
|
||||
undefined, [modifier], 'decorators', undefined, undefined, initializer);
|
||||
const prop =
|
||||
createPropertyDeclaration([modifier], 'decorators', undefined, undefined, initializer);
|
||||
addJSDocTypeAnnotation(prop, DECORATOR_INVOCATION_JSDOC_TYPE);
|
||||
return prop;
|
||||
}
|
||||
@@ -319,9 +320,9 @@ export function getDownlevelDecoratorsTransform(
|
||||
decorators.map(deco => extractMetadataFromSingleDecorator(deco, diagnostics)))));
|
||||
}
|
||||
const initializer = ts.factory.createObjectLiteralExpression(entries, true);
|
||||
const prop = ts.factory.createPropertyDeclaration(
|
||||
undefined, [ts.factory.createToken(ts.SyntaxKind.StaticKeyword)], 'propDecorators',
|
||||
undefined, undefined, initializer);
|
||||
const prop = createPropertyDeclaration(
|
||||
[ts.factory.createToken(ts.SyntaxKind.StaticKeyword)], 'propDecorators', undefined,
|
||||
undefined, initializer);
|
||||
addJSDocTypeAnnotation(prop, `!Object<string, ${DECORATOR_INVOCATION_JSDOC_TYPE}>`);
|
||||
return prop;
|
||||
}
|
||||
@@ -422,9 +423,20 @@ export function getDownlevelDecoratorsTransform(
|
||||
|
||||
const name = (element.name as ts.Identifier).text;
|
||||
const mutable = ts.getMutableClone(element);
|
||||
(mutable as any).decorators = decoratorsToKeep.length ?
|
||||
ts.setTextRange(ts.factory.createNodeArray(decoratorsToKeep), mutable.decorators) :
|
||||
undefined;
|
||||
|
||||
if (IS_AFTER_TS_48) {
|
||||
// As of TS 4.8, the decorators are part of the `modifiers` array.
|
||||
(mutable as any).modifiers = decoratorsToKeep.length ?
|
||||
ts.setTextRange(
|
||||
ts.factory.createNodeArray(
|
||||
combineModifiers(decoratorsToKeep, getModifiers(mutable))),
|
||||
mutable.modifiers) :
|
||||
undefined;
|
||||
} else {
|
||||
(mutable as any).decorators = decoratorsToKeep.length ?
|
||||
ts.setTextRange(ts.factory.createNodeArray(decoratorsToKeep), mutable.decorators) :
|
||||
undefined;
|
||||
}
|
||||
return [name, mutable, toLower];
|
||||
}
|
||||
|
||||
@@ -463,15 +475,16 @@ export function getDownlevelDecoratorsTransform(
|
||||
paramInfo!.type = param.type;
|
||||
}
|
||||
parametersInfo.push(paramInfo);
|
||||
const newParam = ts.factory.updateParameterDeclaration(
|
||||
const newParam = updateParameterDeclaration(
|
||||
param,
|
||||
// Must pass 'undefined' to avoid emitting decorator metadata.
|
||||
decoratorsToKeep.length ? decoratorsToKeep : undefined, param.modifiers,
|
||||
combineModifiers(
|
||||
// Must pass 'undefined' to avoid emitting decorator metadata.
|
||||
decoratorsToKeep.length ? decoratorsToKeep : undefined, getModifiers(param)),
|
||||
param.dotDotDotToken, param.name, param.questionToken, param.type, param.initializer);
|
||||
newParameters.push(newParam);
|
||||
}
|
||||
const updated = ts.factory.updateConstructorDeclaration(
|
||||
ctor, ctor.decorators, ctor.modifiers, newParameters, ctor.body);
|
||||
const updated =
|
||||
updateConstructorDeclaration(ctor, getModifiers(ctor), newParameters, ctor.body);
|
||||
return [updated, parametersInfo];
|
||||
}
|
||||
|
||||
@@ -519,7 +532,7 @@ export function getDownlevelDecoratorsTransform(
|
||||
// decorators that will never be Angular decorators. So we cannot rely on it to capture all
|
||||
// the decorators that should be kept. Instead we start off with a set of the raw decorators
|
||||
// on the class, and only remove the ones that have been identified for downleveling.
|
||||
const decoratorsToKeep = new Set<ts.Decorator>(classDecl.decorators);
|
||||
const decoratorsToKeep = new Set<ts.Decorator>(getDecorators(classDecl));
|
||||
const possibleAngularDecorators = host.getDecoratorsOfDeclaration(classDecl) || [];
|
||||
|
||||
let hasAngularDecorator = false;
|
||||
@@ -561,10 +574,12 @@ export function getDownlevelDecoratorsTransform(
|
||||
ts.factory.createNodeArray(newMembers, classDecl.members.hasTrailingComma),
|
||||
classDecl.members);
|
||||
|
||||
return ts.factory.updateClassDeclaration(
|
||||
classDecl, decoratorsToKeep.size ? Array.from(decoratorsToKeep) : undefined,
|
||||
classDecl.modifiers, classDecl.name, classDecl.typeParameters, classDecl.heritageClauses,
|
||||
members);
|
||||
return updateClassDeclaration(
|
||||
classDecl,
|
||||
combineModifiers(
|
||||
decoratorsToKeep.size ? Array.from(decoratorsToKeep) : undefined,
|
||||
getModifiers(classDecl)),
|
||||
classDecl.name, classDecl.typeParameters, classDecl.heritageClauses, members);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,7 +26,7 @@ const MIN_TS_VERSION = '4.6.2';
|
||||
* Note: this check is disabled in g3, search for
|
||||
* `angularCompilerOptions.disableTypeScriptVersionCheck` config param value in g3.
|
||||
*/
|
||||
const MAX_TS_VERSION = '4.8.0';
|
||||
const MAX_TS_VERSION = '4.9.0';
|
||||
|
||||
/**
|
||||
* The currently used version of TypeScript, which can be adjusted for testing purposes using
|
||||
|
||||
@@ -625,7 +625,7 @@ describe('downlevel decorator transform', () => {
|
||||
export class MyDir {
|
||||
constructor(@Inject('$state') param: angular.IState,
|
||||
@Inject('$overlay') other: IOverlay,
|
||||
@Inject('$default') default: TypeFromDefaultImport,
|
||||
@Inject('$default') fromDefaultImport: TypeFromDefaultImport,
|
||||
@Inject('$keyCodes') keyCodes: KeyCodes) {}
|
||||
}
|
||||
`);
|
||||
@@ -652,6 +652,7 @@ describe('downlevel decorator transform', () => {
|
||||
if (ts.isClassDeclaration(node) || ts.isClassElement(node)) {
|
||||
const cloned = ts.getMutableClone(node);
|
||||
(cloned.decorators as undefined) = undefined;
|
||||
(cloned.modifiers as undefined) = undefined;
|
||||
return cloned;
|
||||
}
|
||||
return ts.visitEachChild(node, visitNode, context);
|
||||
|
||||
@@ -96,7 +96,8 @@ describe('element discovery', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const host = fixture.nativeElement;
|
||||
const [section, div1, p, div2] = Array.from(host.querySelectorAll('section, div, p'));
|
||||
const [section, div1, p, div2] =
|
||||
Array.from<HTMLElement>(host.querySelectorAll('section, div, p'));
|
||||
|
||||
expect(section.nodeName.toLowerCase()).toBe('section');
|
||||
expect(readPatchedData(section)).toBeTruthy();
|
||||
|
||||
@@ -64,7 +64,7 @@ abstract class OverrideResolver<T> implements Resolver<T> {
|
||||
}
|
||||
|
||||
resolve(type: Type<any>): T|null {
|
||||
let resolved = this.resolved.get(type) || null;
|
||||
let resolved: T|null = this.resolved.get(type) || null;
|
||||
|
||||
if (!resolved) {
|
||||
resolved = this.getAnnotation(type);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"mocha": "^10.0.0",
|
||||
"mock-require": "3.0.3",
|
||||
"promises-aplus-tests": "^2.1.2",
|
||||
"typescript": "~4.7.2"
|
||||
"typescript": "4.8.1-rc"
|
||||
},
|
||||
"scripts": {
|
||||
"closuretest": "./scripts/closure/closure_compiler.sh",
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
"zone.js": "file:../../../../dist/bin/packages/zone.js/npm_package"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "~4.7.2"
|
||||
"typescript": "4.8.1-rc"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4049,10 +4049,10 @@ typedarray-to-buffer@^3.1.5:
|
||||
dependencies:
|
||||
is-typedarray "^1.0.0"
|
||||
|
||||
typescript@~4.7.2:
|
||||
version "4.7.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
|
||||
integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
|
||||
typescript@4.8.1-rc:
|
||||
version "4.8.1-rc"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.1-rc.tgz#2baff2b14b916f06a97effbfcf59e46bab93e48a"
|
||||
integrity sha512-ZoXadPUeEe1XOZe6CHG/QHZ6IFeRjrfzkpraRi9HOpGH0UOG/WaUrKvtSwDFigG8GuDA4zsDQHEZyqhmlCIyEw==
|
||||
|
||||
unbox-primitive@^1.0.2:
|
||||
version "1.0.2"
|
||||
|
||||
Reference in New Issue
Block a user