Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1647 #1648

Merged
merged 3 commits into from Feb 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 30 additions & 55 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -134,8 +134,8 @@
"semver": "^7.1.3",
"throat": "^6.0.1",
"typedoc": "^0.22.10",
"typescript": "4.5.2",
"typescript-json-schema": "^0.51.0",
"typescript": "4.5.5",
"typescript-json-schema": "^0.53.0",
"util.promisify": "^1.0.1"
},
"peerDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Expand Up @@ -605,7 +605,7 @@ export function create(rawOptions: CreateOptions = {}): Service {
const projectLocalResolveHelper =
createProjectLocalResolveHelper(relativeToPath);
const compiler = projectLocalResolveHelper(name || 'typescript', true);
const ts: typeof _ts = attemptRequireWithV8CompileCache(require, compiler);
const ts: TSCommon = attemptRequireWithV8CompileCache(require, compiler);
return { compiler, ts, projectLocalResolveHelper };
}

Expand Down
90 changes: 54 additions & 36 deletions src/resolver-functions.ts
@@ -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;
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,37 @@ 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 as any as TSInternal).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