From f09024d65551a9f6bfc57bfac688102d937bf03b Mon Sep 17 00:00:00 2001 From: John Reilly Date: Tue, 1 Mar 2022 18:26:54 +0000 Subject: [PATCH] fix: cater for change in resolveTypeReferenceDirective API in TypeScript 4.7 (#1422) * speculative * v9.2.7 * node 16 --- .github/workflows/push.yml | 4 +- .github/workflows/release.yml | 2 +- CHANGELOG.md | 8 +++ package.json | 2 +- src/interfaces.ts | 25 ++++++++ src/servicesHost.ts | 104 +++++++++++++++++++++------------- 6 files changed, 103 insertions(+), 42 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 236a059bc..39554803b 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -48,7 +48,7 @@ jobs: name: Execution Tests Ubuntu strategy: matrix: - node: [12, 14] + node: [14, 16] ts: [3.8.3, 3.9.3, 4.0.3, 4.1.5, 4.2.4, 4.3.2, 4.4.2, 4.5.2, next] runs-on: ubuntu-latest steps: @@ -75,7 +75,7 @@ jobs: name: Execution Tests Windows strategy: matrix: - node: [12, 14] + node: [14, 16] ts: [3.8.3, 3.9.3, 4.0.3, 4.1.5, 4.2.4, 4.3.2, 4.4.2, 4.5.2, next] runs-on: windows-latest steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a09340ce3..b3eee8451 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: - name: install node uses: actions/setup-node@v1 with: - node-version: 14 + node-version: 16 registry-url: https://registry.npmjs.org/ - name: install diff --git a/CHANGELOG.md b/CHANGELOG.md index 04be63afc..fdeb5b584 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## v9.2.7 + +* [cater for change in resolveTypeReferenceDirective API in TypeScript 4.7](https://github.com/TypeStrong/ts-loader/pull/1422) [#1421] - thanks @johnny_reilly and @cspotcode for inspiration in ts-node work here: https://github.com/TypeStrong/ts-node/pull/1648 + +## v9.2.6 + +* [Docs fix for thread-loader / history](https://github.com/TypeStrong/ts-loader/pull/1377) - thanks @johnnyreilly + ## v9.2.5 * [Add function to get the latest program](https://github.com/TypeStrong/ts-loader/pull/1352) - thanks @Zn4rK diff --git a/package.json b/package.json index acecff837..7033e4a30 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts-loader", - "version": "9.2.6", + "version": "9.2.7", "description": "TypeScript loader for webpack", "main": "index.js", "types": "dist", diff --git a/src/interfaces.ts b/src/interfaces.ts index 301705e13..0dbba06ab 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -307,4 +307,29 @@ export interface ResolvedModule { isExternalLibraryImport?: boolean; } +export interface TSCommon { + // Changed in TS 4.7 + resolveTypeReferenceDirective( + typeReferenceDirectiveName: string, + containingFile: string | undefined, + options: typescript.CompilerOptions, + host: typescript.ModuleResolutionHost, + redirectedReference?: typescript.ResolvedProjectReference, + cache?: typescript.TypeReferenceDirectiveResolutionCache, + resolutionMode?: typescript.SourceFile['impliedNodeFormat'] + ): typescript.ResolvedTypeReferenceDirectiveWithFailedLookupLocations; +} + +/** + * Compiler APIs we use that are marked internal and not included in TypeScript's public API declarations + * @internal + */ +export interface TSInternal { + // Added in TS 4.7 + getModeForFileReference?: ( + ref: typescript.FileReference | string, + containingFileMode: typescript.SourceFile['impliedNodeFormat'] + ) => typescript.SourceFile['impliedNodeFormat']; +} + export type Severity = 'error' | 'warning'; diff --git a/src/servicesHost.ts b/src/servicesHost.ts index 7a7b0bf89..3cd9b550d 100644 --- a/src/servicesHost.ts +++ b/src/servicesHost.ts @@ -17,7 +17,9 @@ import { ServiceHostWhichMayBeCacheable, SolutionBuilderWithWatchHost, SolutionDiagnostics, + TSCommon, TSInstance, + TSInternal, WatchCallbacks, WatchFactory, WatchHost, @@ -175,9 +177,10 @@ export function makeServicesHost( return file.version.toString(); } - const outputFileAndKey = instance.solutionBuilderHost?.getOutputFileAndKeyFromReferencedProject( - fileName - ); + const outputFileAndKey = + instance.solutionBuilderHost?.getOutputFileAndKeyFromReferencedProject( + fileName + ); if (outputFileAndKey !== undefined) { instance.solutionBuilderHost!.outputAffectingInstanceVersion.set( outputFileAndKey.key, @@ -198,9 +201,10 @@ export function makeServicesHost( if (file === undefined) { if (instance.solutionBuilderHost) { - const outputFileAndKey = instance.solutionBuilderHost.getOutputFileTextAndKeyFromReferencedProject( - fileName - ); + const outputFileAndKey = + instance.solutionBuilderHost.getOutputFileTextAndKeyFromReferencedProject( + fileName + ); if (outputFileAndKey !== undefined) { instance.solutionBuilderHost!.outputAffectingInstanceVersion.set( outputFileAndKey.key, @@ -288,16 +292,20 @@ function makeResolvers( ); const resolveTypeReferenceDirectives = ( - typeDirectiveNames: string[], + typeDirectiveNames: string[] | readonly typescript.FileReference[], containingFile: string, - redirectedReference?: typescript.ResolvedProjectReference + redirectedReference: typescript.ResolvedProjectReference | undefined, + options: typescript.CompilerOptions, + containingFileMode?: typescript.SourceFile['impliedNodeFormat'] | undefined // new impliedNodeFormat is accepted by compilerHost ): (typescript.ResolvedTypeReferenceDirective | undefined)[] => typeDirectiveNames.map( directive => resolveTypeReferenceDirective( directive, containingFile, - redirectedReference + options, + redirectedReference, + containingFileMode ).resolvedTypeReferenceDirective ); @@ -312,9 +320,12 @@ function createWatchFactory( filePathKeyMapper: (fileName: string) => FilePathKey, compiler: typeof typescript ): WatchFactory { - const watchedFiles: WatchCallbacks = new Map(); - const watchedDirectories: WatchCallbacks = new Map(); - const watchedDirectoriesRecursive: WatchCallbacks = new Map(); + const watchedFiles: WatchCallbacks = + new Map(); + const watchedDirectories: WatchCallbacks = + new Map(); + const watchedDirectoriesRecursive: WatchCallbacks = + new Map(); return { watchedFiles, @@ -473,13 +484,8 @@ export function makeWatchHost( instance: TSInstance, projectReferences?: ReadonlyArray ) { - const { - compiler, - compilerOptions, - files, - otherFiles, - filePathKeyMapper, - } = instance; + const { compiler, compilerOptions, files, otherFiles, filePathKeyMapper } = + instance; const { watchFile, watchDirectory, invokeFileWatcher } = createWatchFactory( filePathKeyMapper, @@ -507,9 +513,10 @@ export function makeWatchHost( readFile: readFileWithCachingText, watchFile: (fileName, callback, pollingInterval, options) => { - const outputFileKey = instance.solutionBuilderHost?.getOutputFileKeyFromReferencedProject( - fileName - ); + const outputFileKey = + instance.solutionBuilderHost?.getOutputFileKeyFromReferencedProject( + fileName + ); if (!outputFileKey || outputFileKey === filePathKeyMapper(fileName)) { return watchFile(fileName, callback, pollingInterval, options); } @@ -1155,9 +1162,11 @@ export function getSolutionErrors(instance: TSInstance, context: string) { } type ResolveTypeReferenceDirective = ( - directive: string, + directive: string | typescript.FileReference, containingFile: string, - redirectedReference?: typescript.ResolvedProjectReference + options: typescript.CompilerOptions, + redirectedReference?: typescript.ResolvedProjectReference, + containingFileMode?: typescript.SourceFile['impliedNodeFormat'] | undefined // new impliedNodeFormat is accepted by compilerHost ) => typescript.ResolvedTypeReferenceDirectiveWithFailedLookupLocations; function makeResolveTypeReferenceDirective( @@ -1172,31 +1181,50 @@ function makeResolveTypeReferenceDirective( if (customResolveTypeReferenceDirective === undefined) { // Until the api is published if ( - (compiler as any).createTypeReferenceDirectiveResolutionCache && + compiler.createTypeReferenceDirectiveResolutionCache !== undefined && !instance.typeReferenceResolutionCache ) { - instance.typeReferenceResolutionCache = (compiler as any).createTypeReferenceDirectiveResolutionCache( - moduleResolutionHost.getCurrentDirectory!(), - createGetCanonicalFileName(instance), - instance.compilerOptions, - instance.moduleResolutionCache?.getPackageJsonInfoCache?.() - ); + instance.typeReferenceResolutionCache = + compiler.createTypeReferenceDirectiveResolutionCache( + moduleResolutionHost.getCurrentDirectory!(), + createGetCanonicalFileName(instance), + instance.compilerOptions, + instance.moduleResolutionCache?.getPackageJsonInfoCache?.() + ); } - return (directive, containingFile, redirectedReference) => - // Until the api is published - (compiler.resolveTypeReferenceDirective as any)( - directive, + return ( + typeDirectiveName, + containingFile, + options, + redirectedReference, + containingFileMode + ) => { + // Copy-pasted from https://github.com/TypeStrong/ts-node/blob/9f789d0d91c6eba30ac7f7aad45194a23b44f159/src/resolver-functions.ts#L139 + const nameIsString = typeof typeDirectiveName === 'string'; + const mode = nameIsString + ? undefined + : (compiler as any as TSInternal).getModeForFileReference!( + typeDirectiveName, + containingFileMode + ); + const strName = nameIsString + ? typeDirectiveName + : typeDirectiveName.fileName.toLowerCase(); + return (compiler as any as TSCommon).resolveTypeReferenceDirective( + strName, containingFile, - compilerOptions, + options, moduleResolutionHost, redirectedReference, - instance.typeReferenceResolutionCache + undefined, + mode ); + }; } return (directive, containingFile) => customResolveTypeReferenceDirective( - directive, + directive as string, // unsure whether we should evolve this further containingFile, compilerOptions, moduleResolutionHost,