build: TypeScript 3.6 compatibility. (#32908)
This PR updates Angular to compile with TypeScript 3.6 while retaining compatibility with TS3.5. We achieve this by inserting several `as any` casts for compatiblity around `ts.CompilerHost` APIs. PR Close #32908
This commit is contained in:
@ -180,8 +180,11 @@ export class CommonJsReflectionHost extends Esm5ReflectionHost {
|
|||||||
private resolveModuleName(moduleName: string, containingFile: ts.SourceFile): ts.SourceFile
|
private resolveModuleName(moduleName: string, containingFile: ts.SourceFile): ts.SourceFile
|
||||||
|undefined {
|
|undefined {
|
||||||
if (this.compilerHost.resolveModuleNames) {
|
if (this.compilerHost.resolveModuleNames) {
|
||||||
const moduleInfo =
|
// FIXME: remove the "as any" cast once on TS3.6.
|
||||||
this.compilerHost.resolveModuleNames([moduleName], containingFile.fileName)[0];
|
const moduleInfo = (this.compilerHost as any)
|
||||||
|
.resolveModuleNames(
|
||||||
|
[moduleName], containingFile.fileName, undefined, undefined,
|
||||||
|
this.program.getCompilerOptions())[0];
|
||||||
return moduleInfo && this.program.getSourceFile(absoluteFrom(moduleInfo.resolvedFileName));
|
return moduleInfo && this.program.getSourceFile(absoluteFrom(moduleInfo.resolvedFileName));
|
||||||
} else {
|
} else {
|
||||||
const moduleInfo = ts.resolveModuleName(
|
const moduleInfo = ts.resolveModuleName(
|
||||||
|
@ -158,8 +158,11 @@ export class UmdReflectionHost extends Esm5ReflectionHost {
|
|||||||
private resolveModuleName(moduleName: string, containingFile: ts.SourceFile): ts.SourceFile
|
private resolveModuleName(moduleName: string, containingFile: ts.SourceFile): ts.SourceFile
|
||||||
|undefined {
|
|undefined {
|
||||||
if (this.compilerHost.resolveModuleNames) {
|
if (this.compilerHost.resolveModuleNames) {
|
||||||
const moduleInfo =
|
// FIXME: remove the "as any" cast once on TS3.6.
|
||||||
this.compilerHost.resolveModuleNames([moduleName], containingFile.fileName)[0];
|
const moduleInfo = (this.compilerHost as any)
|
||||||
|
.resolveModuleNames(
|
||||||
|
[moduleName], containingFile.fileName, undefined, undefined,
|
||||||
|
this.program.getCompilerOptions())[0];
|
||||||
return moduleInfo && this.program.getSourceFile(absoluteFrom(moduleInfo.resolvedFileName));
|
return moduleInfo && this.program.getSourceFile(absoluteFrom(moduleInfo.resolvedFileName));
|
||||||
} else {
|
} else {
|
||||||
const moduleInfo = ts.resolveModuleName(
|
const moduleInfo = ts.resolveModuleName(
|
||||||
@ -281,4 +284,4 @@ function findNamespaceOfIdentifier(id: ts.Identifier): ts.Identifier|null {
|
|||||||
|
|
||||||
export function stripParentheses(node: ts.Node): ts.Node {
|
export function stripParentheses(node: ts.Node): ts.Node {
|
||||||
return ts.isParenthesizedExpression(node) ? node.expression : node;
|
return ts.isParenthesizedExpression(node) ? node.expression : node;
|
||||||
}
|
}
|
||||||
|
@ -457,8 +457,8 @@ export class MetadataCollector {
|
|||||||
left: {
|
left: {
|
||||||
__symbolic: 'select',
|
__symbolic: 'select',
|
||||||
expression: recordEntry({__symbolic: 'reference', name: enumName}, node), name
|
expression: recordEntry({__symbolic: 'reference', name: enumName}, node), name
|
||||||
} as any,
|
},
|
||||||
};
|
} as any;
|
||||||
} else {
|
} else {
|
||||||
nextDefaultValue =
|
nextDefaultValue =
|
||||||
recordEntry(errorSym('Unsupported enum member name', member.name), node);
|
recordEntry(errorSym('Unsupported enum member name', member.name), node);
|
||||||
|
@ -32,11 +32,14 @@ export interface ShimGenerator {
|
|||||||
export class GeneratedShimsHostWrapper implements ts.CompilerHost {
|
export class GeneratedShimsHostWrapper implements ts.CompilerHost {
|
||||||
constructor(private delegate: ts.CompilerHost, private shimGenerators: ShimGenerator[]) {
|
constructor(private delegate: ts.CompilerHost, private shimGenerators: ShimGenerator[]) {
|
||||||
if (delegate.resolveModuleNames !== undefined) {
|
if (delegate.resolveModuleNames !== undefined) {
|
||||||
this.resolveModuleNames =
|
// FIXME: TypeScript 3.6 adds an "options" argument that the code below passes on, but which
|
||||||
(moduleNames: string[], containingFile: string, reusedNames?: string[],
|
// still makes the method incompatible with TS3.5. Remove the "as any" cast once fully on 3.6.
|
||||||
redirectedReference?: ts.ResolvedProjectReference) =>
|
((this as ts.CompilerHost) as any).resolveModuleNames =
|
||||||
delegate.resolveModuleNames !(
|
(moduleNames: string[], containingFile: string, reusedNames: (string[] | undefined),
|
||||||
moduleNames, containingFile, reusedNames, redirectedReference);
|
redirectedReference: (ts.ResolvedProjectReference | undefined), options: any) =>
|
||||||
|
(delegate as any)
|
||||||
|
.resolveModuleNames !(
|
||||||
|
moduleNames, containingFile, reusedNames, redirectedReference, options);
|
||||||
}
|
}
|
||||||
if (delegate.resolveTypeReferenceDirectives) {
|
if (delegate.resolveTypeReferenceDirectives) {
|
||||||
// Backward compatibility with TypeScript 2.9 and older since return
|
// Backward compatibility with TypeScript 2.9 and older since return
|
||||||
@ -56,10 +59,6 @@ export class GeneratedShimsHostWrapper implements ts.CompilerHost {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveModuleNames?:
|
|
||||||
(moduleNames: string[], containingFile: string, reusedNames?: string[],
|
|
||||||
redirectedReference?: ts.ResolvedProjectReference) => (ts.ResolvedModule | undefined)[];
|
|
||||||
|
|
||||||
resolveTypeReferenceDirectives?:
|
resolveTypeReferenceDirectives?:
|
||||||
(names: string[], containingFile: string) => ts.ResolvedTypeReferenceDirective[];
|
(names: string[], containingFile: string) => ts.ResolvedTypeReferenceDirective[];
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ describe('shim host', () => {
|
|||||||
const delegate = {} as unknown as ts.CompilerHost;
|
const delegate = {} as unknown as ts.CompilerHost;
|
||||||
const shimsHost = new GeneratedShimsHostWrapper(delegate, []);
|
const shimsHost = new GeneratedShimsHostWrapper(delegate, []);
|
||||||
|
|
||||||
expect(shimsHost.resolveModuleNames).not.toBeDefined();
|
// FIXME: re-enable once fully on TS3.6.
|
||||||
|
// expect(shimsHost.resolveModuleNames).not.toBeDefined();
|
||||||
expect(shimsHost.resolveTypeReferenceDirectives).not.toBeDefined();
|
expect(shimsHost.resolveTypeReferenceDirectives).not.toBeDefined();
|
||||||
expect(shimsHost.directoryExists).not.toBeDefined();
|
expect(shimsHost.directoryExists).not.toBeDefined();
|
||||||
expect(shimsHost.getDirectories).not.toBeDefined();
|
expect(shimsHost.getDirectories).not.toBeDefined();
|
||||||
@ -29,7 +30,8 @@ describe('shim host', () => {
|
|||||||
} as unknown as ts.CompilerHost;
|
} as unknown as ts.CompilerHost;
|
||||||
const shimsHost = new GeneratedShimsHostWrapper(delegate, []);
|
const shimsHost = new GeneratedShimsHostWrapper(delegate, []);
|
||||||
|
|
||||||
expect(shimsHost.resolveModuleNames).toBeDefined();
|
// FIXME: re-enable once fully on TS3.6.
|
||||||
|
// expect(shimsHost.resolveModuleNames).toBeDefined();
|
||||||
expect(shimsHost.resolveTypeReferenceDirectives).toBeDefined();
|
expect(shimsHost.resolveTypeReferenceDirectives).toBeDefined();
|
||||||
expect(shimsHost.directoryExists).toBeDefined();
|
expect(shimsHost.directoryExists).toBeDefined();
|
||||||
expect(shimsHost.getDirectories).toBeDefined();
|
expect(shimsHost.getDirectories).toBeDefined();
|
||||||
|
@ -113,7 +113,10 @@ export function resolveModuleName(
|
|||||||
moduleName: string, containingFile: string, compilerOptions: ts.CompilerOptions,
|
moduleName: string, containingFile: string, compilerOptions: ts.CompilerOptions,
|
||||||
compilerHost: ts.CompilerHost): ts.ResolvedModule|undefined {
|
compilerHost: ts.CompilerHost): ts.ResolvedModule|undefined {
|
||||||
if (compilerHost.resolveModuleNames) {
|
if (compilerHost.resolveModuleNames) {
|
||||||
return compilerHost.resolveModuleNames([moduleName], containingFile)[0];
|
// FIXME: Additional parameters are required in TS3.6, but ignored in 3.5.
|
||||||
|
// Remove the any cast once fully on TS3.6.
|
||||||
|
return (compilerHost as any)
|
||||||
|
.resolveModuleNames([moduleName], containingFile, undefined, undefined, compilerOptions)[0];
|
||||||
} else {
|
} else {
|
||||||
return ts.resolveModuleName(moduleName, containingFile, compilerOptions, compilerHost)
|
return ts.resolveModuleName(moduleName, containingFile, compilerOptions, compilerHost)
|
||||||
.resolvedModule;
|
.resolvedModule;
|
||||||
|
@ -277,7 +277,7 @@ export class PlatformRef {
|
|||||||
const ngZoneInjector = Injector.create(
|
const ngZoneInjector = Injector.create(
|
||||||
{providers: providers, parent: this.injector, name: moduleFactory.moduleType.name});
|
{providers: providers, parent: this.injector, name: moduleFactory.moduleType.name});
|
||||||
const moduleRef = <InternalNgModuleRef<M>>moduleFactory.create(ngZoneInjector);
|
const moduleRef = <InternalNgModuleRef<M>>moduleFactory.create(ngZoneInjector);
|
||||||
const exceptionHandler: ErrorHandler = moduleRef.injector.get(ErrorHandler, null);
|
const exceptionHandler: ErrorHandler|null = moduleRef.injector.get(ErrorHandler, null);
|
||||||
if (!exceptionHandler) {
|
if (!exceptionHandler) {
|
||||||
throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?');
|
throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?');
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,9 @@ export interface DirectiveType<T> extends Type<T> {
|
|||||||
ngFactoryDef: () => T;
|
ngFactoryDef: () => T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum DirectiveDefFlags {ContentQuery = 0b10}
|
export enum DirectiveDefFlags {
|
||||||
|
ContentQuery = 0b10
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A subclass of `Type` which has a static `ngPipeDef`:`PipeDef` field making it
|
* A subclass of `Type` which has a static `ngPipeDef`:`PipeDef` field making it
|
||||||
|
@ -225,7 +225,9 @@ export function createContainerRef(
|
|||||||
ngModuleRef?: viewEngine_NgModuleRef<any>|undefined): viewEngine_ComponentRef<C> {
|
ngModuleRef?: viewEngine_NgModuleRef<any>|undefined): viewEngine_ComponentRef<C> {
|
||||||
const contextInjector = injector || this.parentInjector;
|
const contextInjector = injector || this.parentInjector;
|
||||||
if (!ngModuleRef && (componentFactory as any).ngModule == null && contextInjector) {
|
if (!ngModuleRef && (componentFactory as any).ngModule == null && contextInjector) {
|
||||||
ngModuleRef = contextInjector.get(viewEngine_NgModuleRef, null);
|
// FIXME: ngModuleRef is optional, so its type allows "undefined", whereas the code
|
||||||
|
// below is passing null for the default/absent value.
|
||||||
|
ngModuleRef = contextInjector.get(viewEngine_NgModuleRef, null as any as undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
const componentRef =
|
const componentRef =
|
||||||
|
@ -268,8 +268,9 @@ export class TestBedRender3 implements TestBed {
|
|||||||
if (token as unknown === TestBedRender3) {
|
if (token as unknown === TestBedRender3) {
|
||||||
return this as any;
|
return this as any;
|
||||||
}
|
}
|
||||||
const result = this.testModuleRef.injector.get(token, UNDEFINED, flags);
|
const result = this.testModuleRef.injector.get(token, UNDEFINED as{}, flags);
|
||||||
return result === UNDEFINED ? this.compiler.injector.get(token, notFoundValue, flags) : result;
|
return result === UNDEFINED ? this.compiler.injector.get(token, notFoundValue, flags) as any :
|
||||||
|
result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @deprecated from v9.0.0 use TestBed.inject */
|
/** @deprecated from v9.0.0 use TestBed.inject */
|
||||||
|
@ -480,7 +480,8 @@ export class TestBedViewEngine implements TestBed {
|
|||||||
// Tests can inject things from the ng module and from the compiler,
|
// Tests can inject things from the ng module and from the compiler,
|
||||||
// but the ng module can't inject things from the compiler and vice versa.
|
// but the ng module can't inject things from the compiler and vice versa.
|
||||||
const result = this._moduleRef.injector.get(token, UNDEFINED, flags);
|
const result = this._moduleRef.injector.get(token, UNDEFINED, flags);
|
||||||
return result === UNDEFINED ? this._compiler.injector.get(token, notFoundValue, flags) : result;
|
return result === UNDEFINED ? this._compiler.injector.get(token, notFoundValue, flags) as any :
|
||||||
|
result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @deprecated from v9.0.0 use TestBed.inject */
|
/** @deprecated from v9.0.0 use TestBed.inject */
|
||||||
|
@ -99,7 +99,7 @@ describe(
|
|||||||
|
|
||||||
xit('should ensure that Promise this is instanceof Promise', () => {
|
xit('should ensure that Promise this is instanceof Promise', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
Promise.call({}, () => null);
|
Promise.call({} as any, () => null);
|
||||||
}).toThrowError('Must be an instanceof Promise.');
|
}).toThrowError('Must be an instanceof Promise.');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user