diff --git a/packages/compiler-cli/src/ngtsc/program.ts b/packages/compiler-cli/src/ngtsc/program.ts index c4914f86abc46..963d4c448cdf4 100644 --- a/packages/compiler-cli/src/ngtsc/program.ts +++ b/packages/compiler-cli/src/ngtsc/program.ts @@ -11,6 +11,7 @@ import * as ts from 'typescript'; import * as api from '../transformers/api'; import {nocollapseHack} from '../transformers/nocollapse_hack'; +import {verifySupportedTypeScriptVersion} from '../typescript_support'; import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ReferencesRegistry} from './annotations'; import {BaseDefDecoratorHandler} from './annotations/src/base_def'; @@ -74,6 +75,10 @@ export class NgtscProgram implements api.Program { constructor( rootNames: ReadonlyArray, private options: api.CompilerOptions, private host: api.CompilerHost, oldProgram?: NgtscProgram) { + if (!options.disableTypeScriptVersionCheck) { + verifySupportedTypeScriptVersion(); + } + if (shouldEnablePerfTracing(options)) { this.perfTracker = PerfTracker.zeroedToNow(); this.perfRecorder = this.perfTracker; diff --git a/packages/compiler-cli/src/transformers/program.ts b/packages/compiler-cli/src/transformers/program.ts index b687dd1b498c6..a3cc752bb4619 100644 --- a/packages/compiler-cli/src/transformers/program.ts +++ b/packages/compiler-cli/src/transformers/program.ts @@ -13,9 +13,9 @@ import * as path from 'path'; import * as ts from 'typescript'; import {TypeCheckHost, translateDiagnostics} from '../diagnostics/translate_diagnostics'; -import {compareVersions} from '../diagnostics/typescript_version'; import {MetadataCollector, ModuleMetadata, createBundleIndexHost} from '../metadata'; import {NgtscProgram} from '../ngtsc/program'; +import {verifySupportedTypeScriptVersion} from '../typescript_support'; import {CompilerHost, CompilerOptions, CustomTransformers, DEFAULT_ERROR_CODE, Diagnostic, DiagnosticMessageChain, EmitFlags, LazyRoute, LibrarySummary, Program, SOURCE, TsEmitArguments, TsEmitCallback, TsMergeEmitResultsCallback} from './api'; import {CodeGenerator, TsCompilerAotCompilerTypeCheckHostAdapter, getOriginalReferences} from './compiler_host'; @@ -67,19 +67,6 @@ const defaultEmitCallback: TsEmitCallback = program.emit( targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers); -/** - * Minimum supported TypeScript version - * ∀ supported typescript version v, v >= MIN_TS_VERSION - */ -const MIN_TS_VERSION = '3.6.4'; - -/** - * Supremum of supported TypeScript versions - * ∀ supported typescript version v, v < MAX_TS_VERSION - * MAX_TS_VERSION is not considered as a supported TypeScript version - */ -const MAX_TS_VERSION = '3.7.0'; - class AngularCompilerProgram implements Program { private rootNames: string[]; private metadataCache: MetadataCache; @@ -116,7 +103,9 @@ class AngularCompilerProgram implements Program { private host: CompilerHost, oldProgram?: Program) { this.rootNames = [...rootNames]; - checkVersion(ts.version, MIN_TS_VERSION, MAX_TS_VERSION, options.disableTypeScriptVersionCheck); + if (!options.disableTypeScriptVersionCheck) { + verifySupportedTypeScriptVersion(); + } this.oldTsProgram = oldProgram ? oldProgram.getTsProgram() : undefined; if (oldProgram) { @@ -864,33 +853,6 @@ class AngularCompilerProgram implements Program { } } -/** - * Checks whether a given version ∈ [minVersion, maxVersion[ - * An error will be thrown if the following statements are simultaneously true: - * - the given version ∉ [minVersion, maxVersion[, - * - the result of the version check is not meant to be bypassed (the parameter disableVersionCheck - * is false) - * - * @param version The version on which the check will be performed - * @param minVersion The lower bound version. A valid version needs to be greater than minVersion - * @param maxVersion The upper bound version. A valid version needs to be strictly less than - * maxVersion - * @param disableVersionCheck Indicates whether version check should be bypassed - * - * @throws Will throw an error if the following statements are simultaneously true: - * - the given version ∉ [minVersion, maxVersion[, - * - the result of the version check is not meant to be bypassed (the parameter disableVersionCheck - * is false) - */ -export function checkVersion( - version: string, minVersion: string, maxVersion: string, - disableVersionCheck: boolean | undefined) { - if ((compareVersions(version, minVersion) < 0 || compareVersions(version, maxVersion) >= 0) && - !disableVersionCheck) { - throw new Error( - `The Angular Compiler requires TypeScript >=${minVersion} and <${maxVersion} but ${version} was found instead.`); - } -} export function createProgram({rootNames, options, host, oldProgram}: { rootNames: ReadonlyArray, diff --git a/packages/compiler-cli/src/typescript_support.ts b/packages/compiler-cli/src/typescript_support.ts new file mode 100644 index 0000000000000..9a4c430ba5568 --- /dev/null +++ b/packages/compiler-cli/src/typescript_support.ts @@ -0,0 +1,59 @@ +/** + * @license + * Copyright Google Inc. 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 ts from 'typescript'; +import {compareVersions} from './diagnostics/typescript_version'; + +/** + * Minimum supported TypeScript version + * ∀ supported typescript version v, v >= MIN_TS_VERSION + */ +const MIN_TS_VERSION = '3.6.4'; + +/** + * Supremum of supported TypeScript versions + * ∀ supported typescript version v, v < MAX_TS_VERSION + * MAX_TS_VERSION is not considered as a supported TypeScript version + */ +const MAX_TS_VERSION = '3.7.0'; + +/** + * The currently used version of TypeScript, which can be adjusted for testing purposes using + * `setTypeScriptVersionForTesting` and `restoreTypeScriptVersionForTesting` below. + */ +let tsVersion = ts.version; + +export function setTypeScriptVersionForTesting(version: string): void { + tsVersion = version; +} + +export function restoreTypeScriptVersionForTesting(): void { + tsVersion = ts.version; +} + +/** + * Checks whether a given version ∈ [minVersion, maxVersion[ + * An error will be thrown if the following statements are simultaneously true: + * - the given version ∉ [minVersion, maxVersion[, + * + * @param version The version on which the check will be performed + * @param minVersion The lower bound version. A valid version needs to be greater than minVersion + * @param maxVersion The upper bound version. A valid version needs to be strictly less than + * maxVersion + * + * @throws Will throw an error if the given version ∉ [minVersion, maxVersion[ + */ +export function checkVersion(version: string, minVersion: string, maxVersion: string) { + if ((compareVersions(version, minVersion) < 0 || compareVersions(version, maxVersion) >= 0)) { + throw new Error( + `The Angular Compiler requires TypeScript >=${minVersion} and <${maxVersion} but ${version} was found instead.`); + } +} + +export function verifySupportedTypeScriptVersion(): void { + checkVersion(tsVersion, MIN_TS_VERSION, MAX_TS_VERSION); +} diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index a38c2c3e71d93..c764535ff0a39 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -13,6 +13,7 @@ import {ErrorCode, ngErrorCode} from '../../src/ngtsc/diagnostics'; import {absoluteFrom} from '../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../src/ngtsc/file_system/testing'; import {LazyRoute} from '../../src/ngtsc/routing'; +import {restoreTypeScriptVersionForTesting, setTypeScriptVersionForTesting} from '../../src/typescript_support'; import {loadStandardTestFiles} from '../helpers/src/mock_file_loading'; import {NgtscTestEnvironment} from './env'; @@ -4766,6 +4767,48 @@ export const Foo = Foo__PRE_R3__; }); }); + describe('disableTypeScriptVersionCheck', () => { + afterEach(() => restoreTypeScriptVersionForTesting()); + + it('produces an error when not supported and version check is enabled', () => { + setTypeScriptVersionForTesting('3.4.0'); + env.tsconfig({disableTypeScriptVersionCheck: false}); + env.write('empty.ts', ''); + + const diags = env.driveDiagnostics(); + expect(diags.length).toBe(1); + expect(diags[0].messageText).toContain('but 3.4.0 was found instead'); + }); + + it('does not produce an error when supported and version check is enabled', () => { + env.tsconfig({disableTypeScriptVersionCheck: false}); + env.write('empty.ts', ''); + + // The TypeScript version is not overwritten, so the version + // that is actually used should be supported + const diags = env.driveDiagnostics(); + expect(diags.length).toBe(0); + }); + + it('does not produce an error when not supported but version check is disabled', () => { + setTypeScriptVersionForTesting('3.4.0'); + env.tsconfig({disableTypeScriptVersionCheck: true}); + env.write('empty.ts', ''); + + const diags = env.driveDiagnostics(); + expect(diags.length).toBe(0); + }); + + it('produces an error when not supported using default configuration', () => { + setTypeScriptVersionForTesting('3.4.0'); + env.write('empty.ts', ''); + + const diags = env.driveDiagnostics(); + expect(diags.length).toBe(1); + expect(diags[0].messageText).toContain('but 3.4.0 was found instead'); + }); + }); + describe('inline resources', () => { it('should process inline