diff --git a/apps/heft/src/plugins/TypeScriptPlugin/EmitFilesPatch.ts b/apps/heft/src/plugins/TypeScriptPlugin/EmitFilesPatch.ts deleted file mode 100644 index ffbf8bf9d07..00000000000 --- a/apps/heft/src/plugins/TypeScriptPlugin/EmitFilesPatch.ts +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { InternalError } from '@rushstack/node-core-library'; -import type * as TTypescript from 'typescript'; -import { - ExtendedTypeScript, - IEmitResolver, - IEmitHost, - IEmitTransformers, - IExtendedSourceFile -} from './internalTypings/TypeScriptInternals'; - -export interface ICachedEmitModuleKind { - moduleKind: TTypescript.ModuleKind; - - outFolderPath: string; - - /** - * File extension to use instead of '.js' for emitted ECMAScript files. - * For example, '.cjs' to indicate commonjs content, or '.mjs' to indicate ECMAScript modules. - */ - jsExtensionOverride: string | undefined; - - /** - * Set to true if this is the emit kind that is specified in the tsconfig.json. - * Declarations are only emitted for the primary module kind. - */ - isPrimary: boolean; -} - -export class EmitFilesPatch { - private static _patchedTs: ExtendedTypeScript | undefined = undefined; - - private static _baseEmitFiles: any | undefined = undefined; // eslint-disable-line - - public static install( - ts: ExtendedTypeScript, - tsconfig: TTypescript.ParsedCommandLine, - moduleKindsToEmit: ICachedEmitModuleKind[], - changedFiles?: Set - ): void { - if (EmitFilesPatch._patchedTs === ts) { - // We already patched this instance of TS - return; - } - - if (EmitFilesPatch._patchedTs !== undefined) { - throw new InternalError( - 'EmitFilesPatch.install() cannot be called without first uninstalling the existing patch' - ); - } - - EmitFilesPatch._patchedTs = ts; - EmitFilesPatch._baseEmitFiles = ts.emitFiles; - - let foundPrimary: boolean = false; - let defaultModuleKind: TTypescript.ModuleKind; - - for (const moduleKindToEmit of moduleKindsToEmit) { - if (moduleKindToEmit.isPrimary) { - if (foundPrimary) { - throw new Error('Multiple primary module emit kinds encountered.'); - } else { - foundPrimary = true; - } - - defaultModuleKind = moduleKindToEmit.moduleKind; - } - } - - // Override the underlying file emitter to run itself once for each flavor - // This is a rather inelegant way to convince the TypeScript compiler not to duplicate parse/link/check - ts.emitFiles = ( - resolver: IEmitResolver, - host: IEmitHost, - targetSourceFile: IExtendedSourceFile | undefined, - emitTransformers: IEmitTransformers, - emitOnlyDtsFiles?: boolean, - onlyBuildInfo?: boolean, - forceDtsEmit?: boolean - ): TTypescript.EmitResult => { - if (onlyBuildInfo || emitOnlyDtsFiles) { - // There should only be one tsBuildInfo and one set of declaration files - return EmitFilesPatch._baseEmitFiles( - resolver, - host, - targetSourceFile, - emitTransformers, - emitOnlyDtsFiles, - onlyBuildInfo, - forceDtsEmit - ); - } else { - if (targetSourceFile && changedFiles) { - changedFiles.add(targetSourceFile); - } - - let defaultModuleKindResult: TTypescript.EmitResult; - const diagnostics: TTypescript.Diagnostic[] = []; - let emitSkipped: boolean = false; - for (const moduleKindToEmit of moduleKindsToEmit) { - const compilerOptions: TTypescript.CompilerOptions = moduleKindToEmit.isPrimary - ? { - ...tsconfig.options - } - : { - ...tsconfig.options, - module: moduleKindToEmit.moduleKind, - outDir: moduleKindToEmit.outFolderPath, - - // Don't emit declarations for secondary module kinds - declaration: false, - declarationMap: false - }; - - if (!compilerOptions.outDir) { - throw new InternalError('Expected compilerOptions.outDir to be assigned'); - } - - const flavorResult: TTypescript.EmitResult = EmitFilesPatch._baseEmitFiles( - resolver, - { - ...host, - writeFile: EmitFilesPatch.wrapWriteFile(host.writeFile, moduleKindToEmit.jsExtensionOverride), - getCompilerOptions: () => compilerOptions - }, - targetSourceFile, - ts.getTransformers(compilerOptions, undefined, emitOnlyDtsFiles), - emitOnlyDtsFiles, - onlyBuildInfo, - forceDtsEmit - ); - - emitSkipped = emitSkipped || flavorResult.emitSkipped; - for (const diagnostic of flavorResult.diagnostics) { - diagnostics.push(diagnostic); - } - - if (moduleKindToEmit.moduleKind === defaultModuleKind) { - defaultModuleKindResult = flavorResult; - } - // Should results be aggregated, in case for whatever reason the diagnostics are not the same? - } - - const mergedDiagnostics: readonly TTypescript.Diagnostic[] = - ts.sortAndDeduplicateDiagnostics(diagnostics); - - return { - ...defaultModuleKindResult!, - diagnostics: mergedDiagnostics, - emitSkipped - }; - } - }; - } - - public static get isInstalled(): boolean { - return this._patchedTs !== undefined; - } - - /** - * Wraps the writeFile callback on the IEmitHost to override the .js extension, if applicable - */ - public static wrapWriteFile( - baseWriteFile: TTypescript.WriteFileCallback, - jsExtensionOverride: string | undefined - ): TTypescript.WriteFileCallback { - if (!jsExtensionOverride) { - return baseWriteFile; - } - - const replacementExtension: string = `${jsExtensionOverride}$1`; - return ( - fileName: string, - data: string, - writeBOM: boolean, - onError?: ((message: string) => void) | undefined, - sourceFiles?: readonly TTypescript.SourceFile[] | undefined - ) => { - return baseWriteFile( - fileName.replace(/\.js(\.map)?$/g, replacementExtension), - data, - writeBOM, - onError, - sourceFiles - ); - }; - } - - public static uninstall(ts: ExtendedTypeScript): void { - if (EmitFilesPatch._patchedTs === undefined) { - throw new InternalError('EmitFilesPatch.uninstall() cannot be called if no patch was installed'); - } - if (ts !== EmitFilesPatch._patchedTs) { - throw new InternalError('EmitFilesPatch.uninstall() called for the wrong object'); - } - - ts.emitFiles = EmitFilesPatch._baseEmitFiles; - - EmitFilesPatch._patchedTs = undefined; - EmitFilesPatch._baseEmitFiles = undefined; - } -} diff --git a/apps/heft/src/plugins/TypeScriptPlugin/TypeScriptBuilder.ts b/apps/heft/src/plugins/TypeScriptPlugin/TypeScriptBuilder.ts index d9f6ea48938..a918def6328 100644 --- a/apps/heft/src/plugins/TypeScriptPlugin/TypeScriptBuilder.ts +++ b/apps/heft/src/plugins/TypeScriptPlugin/TypeScriptBuilder.ts @@ -5,12 +5,11 @@ import * as crypto from 'crypto'; import * as path from 'path'; import * as semver from 'semver'; import { - FileSystemStats, ITerminal, JsonFile, IPackageJson, ITerminalProvider, - FileSystem, + InternalError, Path, Async, FileError @@ -31,13 +30,30 @@ import { Tslint } from './Tslint'; import { Eslint } from './Eslint'; import { IScopedLogger } from '../../pluginFramework/logging/ScopedLogger'; -import { EmitFilesPatch, ICachedEmitModuleKind } from './EmitFilesPatch'; -import { HeftSession } from '../../pluginFramework/HeftSession'; +import type { HeftSession } from '../../pluginFramework/HeftSession'; import { EmitCompletedCallbackManager } from './EmitCompletedCallbackManager'; import { ISharedTypeScriptConfiguration } from './TypeScriptPlugin'; import { TypeScriptCachedFileSystem } from '../../utilities/fileSystem/TypeScriptCachedFileSystem'; import { LinterBase } from './LinterBase'; +interface ICachedEmitModuleKind { + moduleKind: TTypescript.ModuleKind; + + outFolderPath: string; + + /** + * File extension to use instead of '.js' for emitted ECMAScript files. + * For example, '.cjs' to indicate commonjs content, or '.mjs' to indicate ECMAScript modules. + */ + jsExtensionOverride: string | undefined; + + /** + * Set to true if this is the emit kind that is specified in the tsconfig.json. + * Declarations are only emitted for the primary module kind. + */ + isPrimary: boolean; +} + interface ILinterWrapper { ts: ExtendedTypeScript; logger: IScopedLogger; @@ -78,8 +94,6 @@ type TSolutionHost = TTypescript.SolutionBuilderHost; -const EMPTY_JSON: object = {}; - interface ICompilerCapabilities { /** * Support for incremental compilation via `ts.createIncrementalProgram()`. @@ -114,8 +128,12 @@ interface IExtendedEmitResult extends TTypescript.EmitResult { const OLDEST_SUPPORTED_TS_MAJOR_VERSION: number = 2; const OLDEST_SUPPORTED_TS_MINOR_VERSION: number = 9; -const NEWEST_SUPPORTED_TS_MAJOR_VERSION: number = 4; -const NEWEST_SUPPORTED_TS_MINOR_VERSION: number = 8; +const NEWEST_SUPPORTED_TS_MAJOR_VERSION: number = 5; +const NEWEST_SUPPORTED_TS_MINOR_VERSION: number = 0; + +// symbols for attaching hidden metadata to ts.Program instances. +const INNER_GET_COMPILER_OPTIONS_SYMBOL: unique symbol = Symbol('getCompilerOptions'); +const INNER_EMIT_SYMBOL: unique symbol = Symbol('emit'); export class TypeScriptBuilder extends SubprocessRunnerBase { private _typescriptVersion!: string; @@ -132,9 +150,9 @@ export class TypeScriptBuilder extends SubprocessRunnerBase = new Set(); private __tsCacheFilePath: string | undefined; - private _tsReadJsonCache: Map = new Map(); private _cachedFileSystem: TypeScriptCachedFileSystem = new TypeScriptCachedFileSystem(); public get filename(): string { @@ -260,6 +278,18 @@ export class TypeScriptBuilder extends SubprocessRunnerBase( measurementName: string, fn: () => TResult @@ -305,6 +335,215 @@ export class TypeScriptBuilder extends SubprocessRunnerBase { + const createMultiEmitBuilderProgram: TTypescript.CreateProgram< + TTypescript.EmitAndSemanticDiagnosticsBuilderProgram + > = ( + fileNames: readonly string[] | undefined, + compilerOptions: TTypescript.CompilerOptions | undefined, + host: TTypescript.CompilerHost | undefined, + oldProgram: TTypescript.EmitAndSemanticDiagnosticsBuilderProgram | undefined, + configFileParsingDiagnostics: readonly TTypescript.Diagnostic[] | undefined, + projectReferences: readonly TTypescript.ProjectReference[] | undefined + ): TTypescript.EmitAndSemanticDiagnosticsBuilderProgram => { + // Reset performance counters + ts.performance.disable(); + ts.performance.enable(); + + this._typescriptTerminal.writeVerboseLine(`Reading program "${compilerOptions!.configFilePath}"`); + + const newProgram: TTypescript.EmitAndSemanticDiagnosticsBuilderProgram = + ts.createEmitAndSemanticDiagnosticsBuilderProgram( + fileNames, + compilerOptions, + host, + oldProgram, + configFileParsingDiagnostics, + projectReferences + ); + + this._logReadPerformance(ts); + + const { emit: originalEmit } = newProgram; + + const emit: TTypescript.Program['emit'] = ( + outerTargetSourceFile?: TTypescript.SourceFile, + outerWriteFile?: TTypescript.WriteFileCallback, + outerCancellationToken?: TTypescript.CancellationToken, + outerEmitOnlyDtsFiles?: boolean, + outerCustomTransformers?: TTypescript.CustomTransformers + ) => { + const innerProgram: TTypescript.Program = newProgram.getProgram(); + + const innerCompilerOptions: TTypescript.CompilerOptions = innerProgram.getCompilerOptions(); + + const { changedFiles } = this._configureProgramForMultiEmit(innerProgram, ts); + + const result: TTypescript.EmitResult = originalEmit.call( + newProgram, + outerTargetSourceFile, + outerWriteFile, + outerCancellationToken, + outerEmitOnlyDtsFiles, + outerCustomTransformers + ); + + (result as IExtendedEmitResult).changedSourceFiles = changedFiles; + + this._typescriptTerminal.writeVerboseLine( + `Emitting program "${innerCompilerOptions!.configFilePath}"` + ); + + this._logEmitPerformance(ts); + + // Reset performance counters + ts.performance.disable(); + ts.performance.enable(); + + return result; + }; + + newProgram.emit = emit; + + return newProgram; + }; + + return createMultiEmitBuilderProgram; + } + + private _configureProgramForMultiEmit( + innerProgram: TTypescript.Program, + ts: ExtendedTypeScript + ): { changedFiles: Set } { + interface IProgramWithMultiEmit extends TTypescript.Program { + // Attach the originals to the Program instance to avoid modifying the same Program twice. + // Don't use WeakMap because this Program could theoretically get a { ... } applied to it. + [INNER_GET_COMPILER_OPTIONS_SYMBOL]?: TTypescript.Program['getCompilerOptions']; + [INNER_EMIT_SYMBOL]?: TTypescript.Program['emit']; + } + + const program: IProgramWithMultiEmit = innerProgram; + + // Check to see if this Program has already been modified. + let { [INNER_EMIT_SYMBOL]: innerEmit, [INNER_GET_COMPILER_OPTIONS_SYMBOL]: innerGetCompilerOptions } = + program; + + if (!innerGetCompilerOptions) { + program[INNER_GET_COMPILER_OPTIONS_SYMBOL] = innerGetCompilerOptions = program.getCompilerOptions; + } + + if (!innerEmit) { + program[INNER_EMIT_SYMBOL] = innerEmit = program.emit; + } + + let foundPrimary: boolean = false; + let defaultModuleKind: TTypescript.ModuleKind; + + const multiEmitMap: Map = new Map(); + for (const moduleKindToEmit of this._moduleKindsToEmit) { + const kindCompilerOptions: TTypescript.CompilerOptions = moduleKindToEmit.isPrimary + ? { + ...innerGetCompilerOptions() + } + : { + ...innerGetCompilerOptions(), + module: moduleKindToEmit.moduleKind, + outDir: moduleKindToEmit.outFolderPath, + + // Don't emit declarations for secondary module kinds + declaration: false, + declarationMap: false + }; + if (!kindCompilerOptions.outDir) { + throw new InternalError('Expected compilerOptions.outDir to be assigned'); + } + multiEmitMap.set(moduleKindToEmit, kindCompilerOptions); + + if (moduleKindToEmit.isPrimary) { + if (foundPrimary) { + throw new Error('Multiple primary module emit kinds encountered.'); + } else { + foundPrimary = true; + } + + defaultModuleKind = moduleKindToEmit.moduleKind; + } + } + + const changedFiles: Set = new Set(); + + program.emit = ( + targetSourceFile?: TTypescript.SourceFile, + writeFile?: TTypescript.WriteFileCallback, + cancellationToken?: TTypescript.CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: TTypescript.CustomTransformers + ) => { + if (emitOnlyDtsFiles) { + return program[INNER_EMIT_SYMBOL]!( + targetSourceFile, + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers + ); + } + + if (targetSourceFile && changedFiles) { + changedFiles.add(targetSourceFile as IExtendedSourceFile); + } + + const originalCompilerOptions: TTypescript.CompilerOptions = + program[INNER_GET_COMPILER_OPTIONS_SYMBOL]!(); + + let defaultModuleKindResult: TTypescript.EmitResult; + const diagnostics: TTypescript.Diagnostic[] = []; + let emitSkipped: boolean = false; + try { + for (const [moduleKindToEmit, kindCompilerOptions] of multiEmitMap) { + program.getCompilerOptions = () => kindCompilerOptions; + // Need to mutate the compiler options for the `module` field specifically, because emitWorker() captures + // options in the closure and passes it to `ts.getTransformers()` + originalCompilerOptions.module = moduleKindToEmit.moduleKind; + const flavorResult: TTypescript.EmitResult = program[INNER_EMIT_SYMBOL]!( + targetSourceFile, + writeFile && wrapWriteFile(writeFile, moduleKindToEmit.jsExtensionOverride), + cancellationToken, + emitOnlyDtsFiles, + customTransformers + ); + + emitSkipped = emitSkipped || flavorResult.emitSkipped; + // Need to aggregate diagnostics because some are impacted by the target module type + for (const diagnostic of flavorResult.diagnostics) { + diagnostics.push(diagnostic); + } + + if (moduleKindToEmit.moduleKind === defaultModuleKind) { + defaultModuleKindResult = flavorResult; + } + } + + const mergedDiagnostics: readonly TTypescript.Diagnostic[] = + ts.sortAndDeduplicateDiagnostics(diagnostics); + + return { + ...defaultModuleKindResult!, + changedSourceFiles: changedFiles, + diagnostics: mergedDiagnostics, + emitSkipped + }; + } finally { + // Restore the original compiler options and module kind for future calls + program.getCompilerOptions = program[INNER_GET_COMPILER_OPTIONS_SYMBOL]!; + originalCompilerOptions.module = defaultModuleKind; + } + }; + return { changedFiles }; + } + private _resolveEslintConfigFilePath(eslintEnabled: boolean): string { const defaultPath: string = path.resolve(this._configuration.buildFolder, '.eslintrc.js'); if (!eslintEnabled) { @@ -324,7 +563,6 @@ export class TypeScriptBuilder extends SubprocessRunnerBase { const _tsconfig: TTypescript.ParsedCommandLine = this._loadTsconfig(ts); this._validateTsconfig(ts, _tsconfig); - EmitFilesPatch.install(ts, _tsconfig, this._moduleKindsToEmit); return { tsconfig: _tsconfig @@ -360,7 +598,6 @@ export class TypeScriptBuilder extends SubprocessRunnerBase { - this._overrideTypeScriptReadJson(ts); const _tsconfig: TTypescript.ParsedCommandLine = this._loadTsconfig(ts); this._validateTsconfig(ts, _tsconfig); @@ -377,19 +614,20 @@ export class TypeScriptBuilder extends SubprocessRunnerBase { + filesToWrite.push({ filePath, data }); + }; + + const { changedFiles } = this._configureProgramForMultiEmit(innerProgram, ts); + + const emitResult: TTypescript.EmitResult = genericProgram.emit(undefined, writeFileCallback); //#endregion this._logEmitPerformance(ts); @@ -437,7 +683,7 @@ export class TypeScriptBuilder extends SubprocessRunnerBase = measureTsPerformanceAsync('Write', () => Async.forEachAsync( - emitResult.filesToWrite, + filesToWrite, async ({ filePath, data }: { filePath: string; data: string }) => this._cachedFileSystem.writeFile(filePath, data, { ensureFolderExists: true }), { concurrency: this._configuration.maxWriteParallelism } @@ -451,23 +697,21 @@ export class TypeScriptBuilder extends SubprocessRunnerBase>[] = []; - const extendedProgram: IExtendedProgram = tsProgram as IExtendedProgram; + const extendedProgram: IExtendedProgram = innerProgram as IExtendedProgram; //#region ESLINT if (eslint) { - lintPromises.push(this._runESlintAsync(eslint, extendedProgram, emitResult.changedSourceFiles)); + lintPromises.push(this._runESlintAsync(eslint, extendedProgram, changedFiles)); } //#endregion //#region TSLINT if (tslint) { - lintPromises.push(this._runTSlintAsync(tslint, extendedProgram, emitResult.changedSourceFiles)); + lintPromises.push(this._runTSlintAsync(tslint, extendedProgram, changedFiles)); } //#endregion const { duration: writeDuration } = await writePromise; - this._typescriptTerminal.writeVerboseLine( - `I/O Write: ${writeDuration}ms (${emitResult.filesToWrite.length} files)` - ); + this._typescriptTerminal.writeVerboseLine(`I/O Write: ${writeDuration}ms (${filesToWrite.length} files)`); // In non-watch mode, notify EmitCompletedCallbackManager once after we complete the compile step this._emitCompletedCallbackManager.callback(); @@ -492,7 +736,6 @@ export class TypeScriptBuilder extends SubprocessRunnerBase { - this._overrideTypeScriptReadJson(ts); const _tsconfig: TTypescript.ParsedCommandLine = this._loadTsconfig(ts); this._validateTsconfig(ts, _tsconfig); @@ -506,9 +749,6 @@ export class TypeScriptBuilder extends SubprocessRunnerBase[] = await Promise.all(lintPromises); this._logDiagnostics(ts, rawDiagnostics, linters); - - EmitFilesPatch.uninstall(ts); } private _logDiagnostics( @@ -783,45 +1021,13 @@ export class TypeScriptBuilder extends SubprocessRunnerBase = new Set(); - EmitFilesPatch.install(ts, tsconfig, this._moduleKindsToEmit, changedFiles); - - const writeFileCallback: TTypescript.WriteFileCallback = (filePath: string, data: string) => { - filesToWrite.push({ filePath, data }); - }; - - const result: TTypescript.EmitResult = genericProgram.emit( - undefined, // Target source file - writeFileCallback - ); - - EmitFilesPatch.uninstall(ts); - - return { - ...result, - changedSourceFiles: changedFiles, - filesToWrite - }; - } - private _validateTsconfig(ts: ExtendedTypeScript, tsconfig: TTypescript.ParsedCommandLine): void { if ( (tsconfig.options.module && !tsconfig.options.outDir) || @@ -1061,8 +1267,8 @@ export class TypeScriptBuilder extends SubprocessRunnerBase = ts.createSolutionBuilderHost( - this._getCachingTypeScriptSystem(ts), - ts.createEmitAndSemanticDiagnosticsBuilderProgram, + ts.sys, + this._getCreateBuilderProgram(ts), reportDiagnostic, reportSolutionBuilderStatus, reportEmitErrorSummary @@ -1076,53 +1282,12 @@ export class TypeScriptBuilder extends SubprocessRunnerBase { - try { - const stats: FileSystemStats = this._cachedFileSystem.getStatistics(directoryPath); - return stats.isDirectory() || stats.isSymbolicLink(); - } catch (error) { - if (FileSystem.isNotExistError(error as Error)) { - return false; - } else { - throw error; - } - } - }, - /** Check if the path exists and is a file */ - fileExists: (filePath: string) => { - try { - const stats: FileSystemStats = this._cachedFileSystem.getStatistics(filePath); - return stats.isFile(); - } catch (error) { - if (FileSystem.isNotExistError(error as Error)) { - return false; - } else { - throw error; - } - } - }, - /* Use the Heft config's build folder because it has corrected casing */ - getCurrentDirectory: () => this._configuration.buildFolder, - getDirectories: (folderPath: string) => { - return this._cachedFileSystem.readFolderFilesAndDirectories(folderPath).directories; - }, - realpath: this._cachedFileSystem.getRealPath.bind(this._cachedFileSystem) - }; - - return sys; - } - private _buildWatchCompilerHost( ts: ExtendedTypeScript, tsconfig: TTypescript.ParsedCommandLine @@ -1145,8 +1310,8 @@ export class TypeScriptBuilder extends SubprocessRunnerBase { - let jsonData: object | undefined = this._tsReadJsonCache.get(filePath); - if (jsonData) { - return jsonData; - } else { - try { - const fileContents: string = this._cachedFileSystem.readFile(filePath); - if (!fileContents) { - jsonData = EMPTY_JSON; - } else { - const parsedFile: ReturnType = ts.parseConfigFileTextToJson( - filePath, - fileContents - ); - if (parsedFile.error) { - jsonData = EMPTY_JSON; - } else { - jsonData = parsedFile.config as object; - } - } - } catch (error) { - jsonData = EMPTY_JSON; - } - - this._tsReadJsonCache.set(filePath, jsonData); - return jsonData; - } - }; - } - private _parseModuleKind(ts: ExtendedTypeScript, moduleKindName: string): TTypescript.ModuleKind { switch (moduleKindName.toLowerCase()) { case 'commonjs': @@ -1235,3 +1369,31 @@ export class TypeScriptBuilder extends SubprocessRunnerBase void) | undefined, + sourceFiles?: readonly TTypescript.SourceFile[] | undefined + ) => { + return baseWriteFile( + fileName.replace(JS_EXTENSION_REGEX, replacementExtension), + data, + writeBOM, + onError, + sourceFiles + ); + }; +} diff --git a/apps/heft/src/plugins/TypeScriptPlugin/internalTypings/TypeScriptInternals.ts b/apps/heft/src/plugins/TypeScriptPlugin/internalTypings/TypeScriptInternals.ts index 95320db78b7..bfbb6d10209 100644 --- a/apps/heft/src/plugins/TypeScriptPlugin/internalTypings/TypeScriptInternals.ts +++ b/apps/heft/src/plugins/TypeScriptPlugin/internalTypings/TypeScriptInternals.ts @@ -3,24 +3,6 @@ import type * as TTypescript from 'typescript'; -// The specifics of these types aren't important -/** - * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/types.ts#L3969-L4010 - */ -export interface IEmitResolver {} - -/** - * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/types.ts#L5969-L5988 - */ -export interface IEmitHost { - writeFile: TTypescript.WriteFileCallback; -} - -/** - * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/types.ts#L3338-L3341 - */ -export interface IEmitTransformers {} - export interface IExtendedProgram extends TTypescript.Program { /** * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/types.ts#L3205 @@ -39,20 +21,16 @@ export interface IExtendedSourceFile extends TTypescript.SourceFile { version: string; } -/** - * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/utilities.ts#L3799-L3803 - */ -export interface IResolveModuleNameResolutionHost { - getCanonicalFileName(p: string): string; - getCommonSourceDirectory(): string; - getCurrentDirectory(): string; -} - export interface IExtendedTypeScript { /** * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L3 */ performance: { + /** + * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L119-L121 + */ + disable(): void; + /** * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L110-L116 */ @@ -79,11 +57,6 @@ export interface IExtendedTypeScript { getCount(measureName: string): number; }; - /** - * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/utilities.ts#L4720-L4734 - */ - readJson(filePath: string): object; - /** * https://github.com/microsoft/TypeScript/blob/782c09d783e006a697b4ba6d1e7ec2f718ce8393/src/compiler/utilities.ts#L6540 */ @@ -103,42 +76,6 @@ export interface IExtendedTypeScript { directoryExists: (path: string) => boolean ): string[]; - /** - * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/emitter.ts#L261-L614 - */ - emitFiles( - resolver: IEmitResolver, - host: IEmitHost, - targetSourceFile: TTypescript.SourceFile | undefined, - emitTransformers: IEmitTransformers, - emitOnlyDtsFiles?: boolean, - onlyBuildInfo?: boolean, - forceDtsEmit?: boolean - ): TTypescript.EmitResult; - - /** - * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/transformer.ts#L30-L35 - */ - getTransformers( - compilerOptions: TTypescript.CompilerOptions, - customTransformers?: TTypescript.CustomTransformers, - emitOnlyDtsFiles?: boolean - ): IEmitTransformers; - - /** - * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/utilities.ts#L6100-L6108 - */ - removeFileExtension(path: string): string; - - /** - * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/utilities.ts#L3826-L3833 - */ - getExternalModuleNameFromPath( - host: IResolveModuleNameResolutionHost, - fileName: string, - referencePath?: string - ): string; - Diagnostics: { // https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/diagnosticMessages.json#L4252-L4255 // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/common/changes/@rushstack/heft/typescript-5-compatibility_2023-02-28-00-08.json b/common/changes/@rushstack/heft/typescript-5-compatibility_2023-02-28-00-08.json new file mode 100644 index 00000000000..a3d15e062a0 --- /dev/null +++ b/common/changes/@rushstack/heft/typescript-5-compatibility_2023-02-28-00-08.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/heft", + "comment": "Remove monkey-patching of TypeScript for compatibility with 5.0. Refactors how the multi-emit logic works.", + "type": "minor" + } + ], + "packageName": "@rushstack/heft" +} \ No newline at end of file