Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
cspotcode committed Feb 19, 2022
1 parent abc616e commit 281f169
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 38 deletions.
87 changes: 51 additions & 36 deletions src/resolver-functions.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { resolve } from 'path';
import type * as _ts from 'typescript';
import type { TSCommon, TSInternal } from './ts-compiler-types';
import type { ProjectLocalResolveHelper } from './util';

/**
* @internal
* In a factory because these are shared across both CompilerHost and LanguageService codepaths
*/
export function createResolverFunctions(kwargs: {
ts: typeof _ts;
host: _ts.ModuleResolutionHost;
ts: TSCommon & TSInternal;
host: TSCommon.ModuleResolutionHost;
cwd: string;
getCanonicalFileName: (filename: string) => string;
config: _ts.ParsedCommandLine;
config: TSCommon.ParsedCommandLine;
projectLocalResolveHelper: ProjectLocalResolveHelper;
}) {
const {
Expand Down Expand Up @@ -58,7 +58,9 @@ export function createResolverFunctions(kwargs: {
* If we need to emit JS for a file, force TS to consider it non-external
*/
const fixupResolvedModule = (
resolvedModule: _ts.ResolvedModule | _ts.ResolvedTypeReferenceDirective
resolvedModule:
| TSCommon.ResolvedModule
| TSCommon.ResolvedTypeReferenceDirective
) => {
const { resolvedFileName } = resolvedModule;
if (resolvedFileName === undefined) return;
Expand All @@ -82,35 +84,36 @@ export function createResolverFunctions(kwargs: {
* Older ts versions do not pass `redirectedReference` nor `options`.
* We must pass `redirectedReference` to newer ts versions, but cannot rely on `options`, hence the weird argument name
*/
const resolveModuleNames: _ts.LanguageServiceHost['resolveModuleNames'] = (
moduleNames: string[],
containingFile: string,
reusedNames: string[] | undefined,
redirectedReference: _ts.ResolvedProjectReference | undefined,
optionsOnlyWithNewerTsVersions: _ts.CompilerOptions
): (_ts.ResolvedModule | undefined)[] => {
return moduleNames.map((moduleName) => {
const { resolvedModule } = ts.resolveModuleName(
moduleName,
containingFile,
config.options,
host,
moduleResolutionCache,
redirectedReference
);
if (resolvedModule) {
fixupResolvedModule(resolvedModule);
}
return resolvedModule;
});
};
const resolveModuleNames: TSCommon.LanguageServiceHost['resolveModuleNames'] =
(
moduleNames: string[],
containingFile: string,
reusedNames: string[] | undefined,
redirectedReference: TSCommon.ResolvedProjectReference | undefined,
optionsOnlyWithNewerTsVersions: TSCommon.CompilerOptions
): (TSCommon.ResolvedModule | undefined)[] => {
return moduleNames.map((moduleName) => {
const { resolvedModule } = ts.resolveModuleName(
moduleName,
containingFile,
config.options,
host,
moduleResolutionCache,
redirectedReference
);
if (resolvedModule) {
fixupResolvedModule(resolvedModule);
}
return resolvedModule;
});
};

// language service never calls this, but TS docs recommend that we implement it
const getResolvedModuleWithFailedLookupLocationsFromCache: _ts.LanguageServiceHost['getResolvedModuleWithFailedLookupLocationsFromCache'] =
const getResolvedModuleWithFailedLookupLocationsFromCache: TSCommon.LanguageServiceHost['getResolvedModuleWithFailedLookupLocationsFromCache'] =
(
moduleName,
containingFile
): _ts.ResolvedModuleWithFailedLookupLocations | undefined => {
): TSCommon.ResolvedModuleWithFailedLookupLocations | undefined => {
const ret = ts.resolveModuleNameFromCache(
moduleName,
containingFile,
Expand All @@ -122,22 +125,34 @@ export function createResolverFunctions(kwargs: {
return ret;
};

const resolveTypeReferenceDirectives: _ts.LanguageServiceHost['resolveTypeReferenceDirectives'] =
const resolveTypeReferenceDirectives: TSCommon.LanguageServiceHost['resolveTypeReferenceDirectives'] =
(
typeDirectiveNames: string[],
typeDirectiveNames: string[] | readonly TSCommon.FileReference[],
containingFile: string,
redirectedReference: _ts.ResolvedProjectReference | undefined,
options: _ts.CompilerOptions
): (_ts.ResolvedTypeReferenceDirective | undefined)[] => {
redirectedReference: TSCommon.ResolvedProjectReference | undefined,
options: TSCommon.CompilerOptions,
containingFileMode?: TSCommon.SourceFile['impliedNodeFormat'] | undefined // new impliedNodeFormat is accepted by compilerHost
): (TSCommon.ResolvedTypeReferenceDirective | undefined)[] => {
// Note: seems to be called with empty typeDirectiveNames array for all files.
// TODO consider using `ts.loadWithTypeDirectiveCache`
return typeDirectiveNames.map((typeDirectiveName) => {
// Copy-pasted from TS source:
const nameIsString = typeof typeDirectiveName === 'string';
const mode = nameIsString
? undefined
: ts.getModeForFileReference!(typeDirectiveName, containingFileMode);
const strName = nameIsString
? typeDirectiveName
: typeDirectiveName.fileName.toLowerCase();
let { resolvedTypeReferenceDirective } =
ts.resolveTypeReferenceDirective(
typeDirectiveName,
strName,
containingFile,
config.options,
host,
redirectedReference
redirectedReference,
undefined,
mode
);
if (typeDirectiveName === 'node' && !resolvedTypeReferenceDirective) {
// Resolve @types/node relative to project first, then __dirname (copy logic from elsewhere / refactor into reusable function)
Expand Down
47 changes: 45 additions & 2 deletions src/ts-compiler-types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import type * as _ts from 'typescript';

/**
* Common TypeScript interfaces between versions.
* Common TypeScript interfaces between versions. We endeavour to write ts-node's own code against these types instead
* of against `import "typescript"`, though we are not yet doing this consistently.
*
* Sometimes typescript@next adds an API we need to use. But we build ts-node against typescript@latest.
* In these cases, we must declare that API explicitly here. Our declarations include the newer typescript@next APIs.
* Importantly, these re-declarations are *not* TypeScript internals. They are public APIs that only exist in
* pre-release versions of typescript.
*/
export interface TSCommon {
version: typeof _ts.version;
Expand All @@ -26,7 +32,16 @@ export interface TSCommon {
createModuleResolutionCache: typeof _ts.createModuleResolutionCache;
resolveModuleName: typeof _ts.resolveModuleName;
resolveModuleNameFromCache: typeof _ts.resolveModuleNameFromCache;
resolveTypeReferenceDirective: typeof _ts.resolveTypeReferenceDirective;
// Changed in TS 4.7
resolveTypeReferenceDirective(
typeReferenceDirectiveName: string,
containingFile: string | undefined,
options: _ts.CompilerOptions,
host: _ts.ModuleResolutionHost,
redirectedReference?: _ts.ResolvedProjectReference,
cache?: _ts.TypeReferenceDirectiveResolutionCache,
resolutionMode?: _ts.SourceFile['impliedNodeFormat']
): _ts.ResolvedTypeReferenceDirectiveWithFailedLookupLocations;
createIncrementalCompilerHost: typeof _ts.createIncrementalCompilerHost;
createSourceFile: typeof _ts.createSourceFile;
getDefaultLibFileName: typeof _ts.getDefaultLibFileName;
Expand All @@ -36,6 +51,29 @@ export interface TSCommon {
Extension: typeof _ts.Extension;
ModuleResolutionKind: typeof _ts.ModuleResolutionKind;
}
export namespace TSCommon {
export interface LanguageServiceHost extends _ts.LanguageServiceHost {
// Modified in 4.7
resolveTypeReferenceDirectives?(
typeDirectiveNames: string[] | _ts.FileReference[],
containingFile: string,
redirectedReference: _ts.ResolvedProjectReference | undefined,
options: _ts.CompilerOptions,
containingFileMode?: _ts.SourceFile['impliedNodeFormat'] | undefined
): (_ts.ResolvedTypeReferenceDirective | undefined)[];
}
export type ModuleResolutionHost = _ts.ModuleResolutionHost;
export type ParsedCommandLine = _ts.ParsedCommandLine;
export type ResolvedModule = _ts.ResolvedModule;
export type ResolvedTypeReferenceDirective =
_ts.ResolvedTypeReferenceDirective;
export type CompilerOptions = _ts.CompilerOptions;
export type ResolvedProjectReference = _ts.ResolvedProjectReference;
export type ResolvedModuleWithFailedLookupLocations =
_ts.ResolvedModuleWithFailedLookupLocations;
export type FileReference = _ts.FileReference;
export type SourceFile = _ts.SourceFile;
}

/**
* Compiler APIs we use that are marked internal and not included in TypeScript's public API declarations
Expand Down Expand Up @@ -69,6 +107,11 @@ export interface TSInternal {
redirectedReference?: _ts.ResolvedProjectReference,
lookupConfig?: boolean
): _ts.ResolvedModuleWithFailedLookupLocations;
// Added in TS 4.7
getModeForFileReference?: (
ref: _ts.FileReference | string,
containingFileMode: _ts.SourceFile['impliedNodeFormat']
) => _ts.SourceFile['impliedNodeFormat'];
}
/** @internal */
export namespace TSInternal {
Expand Down

0 comments on commit 281f169

Please sign in to comment.