Skip to content

Commit

Permalink
Eliminiate custom TS System instance (#680)
Browse files Browse the repository at this point in the history
  • Loading branch information
geigerzaehler committed Jun 16, 2024
1 parent ef2464d commit d7325c6
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 83 deletions.
10 changes: 3 additions & 7 deletions packages/knip/src/typescript/createHosts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import path from 'node:path';
import ts from 'typescript';
import { getCompilerExtensions } from '../compilers/index.js';
import type { AsyncCompilers, SyncCompilers } from '../compilers/types.js';
import { FOREIGN_FILE_EXTENSIONS } from '../constants.js';
import type { ToSourceFilePath } from '../util/to-source-path.js';
import { SourceFileManager } from './SourceFileManager.js';
import { createCustomModuleResolver } from './resolveModuleNames.js';
import { createCustomSys } from './sys.js';

const libLocation = path.dirname(ts.getDefaultLibFilePath({}));

Expand All @@ -33,9 +31,7 @@ export const createHosts = ({
}: CreateHostsOptions) => {
const fileManager = new SourceFileManager({ compilers, isSkipLibs });
const compilerExtensions = getCompilerExtensions(compilers);
const sys = createCustomSys(cwd, [...compilerExtensions, ...FOREIGN_FILE_EXTENSIONS]);
const resolveModuleNames = createCustomModuleResolver(
sys,
compilerOptions,
compilerExtensions,
toSourceFilePath,
Expand All @@ -47,10 +43,10 @@ export const createHosts = ({
getScriptFileNames: () => Array.from(entryPaths),
getScriptVersion: () => '0',
getScriptSnapshot: (fileName: string) => fileManager.getSnapshot(fileName),
getCurrentDirectory: sys.getCurrentDirectory,
getCurrentDirectory: () => cwd,
getDefaultLibFileName: ts.getDefaultLibFilePath,
readFile: sys.readFile,
fileExists: sys.fileExists,
readFile: ts.sys.readFile,
fileExists: ts.sys.fileExists,
resolveModuleNames,
};

Expand Down
73 changes: 26 additions & 47 deletions packages/knip/src/typescript/resolveModuleNames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ import { existsSync } from 'node:fs';
import { isBuiltin } from 'node:module';
import { createMatchPath } from 'tsconfig-paths';
import ts from 'typescript';
import { DEFAULT_EXTENSIONS, FOREIGN_FILE_EXTENSIONS } from '../constants.js';
import { DEFAULT_EXTENSIONS } from '../constants.js';
import { timerify } from '../util/Performance.js';
import { sanitizeSpecifier } from '../util/modules.js';
import { dirname, extname, isAbsolute, isInNodeModules, join } from '../util/path.js';
import { dirname, extname, isAbsolute, isInNodeModules, join, toPosix } from '../util/path.js';
import { resolveSync } from '../util/resolve.js';
import type { ToSourceFilePath } from '../util/to-source-path.js';
import { isDeclarationFileExtension } from './ast-helpers.js';
import { ensureRealFilePath, isVirtualFilePath } from './sys.js';

const resolutionCache = new Map<string, ts.ResolvedModuleFull | undefined>();

Expand All @@ -28,13 +27,13 @@ const fileExists = (name: string, containingFile: string) => {
export type ResolveModuleNames = ReturnType<typeof createCustomModuleResolver>;

export function createCustomModuleResolver(
customSys: typeof ts.sys,
compilerOptions: ts.CompilerOptions,
virtualFileExtensions: string[],
customCompilerExtensions: string[],
toSourceFilePath: ToSourceFilePath,
useCache = true
) {
const extensions = [...DEFAULT_EXTENSIONS, ...virtualFileExtensions];
const customCompilerExtensionsSet = new Set(customCompilerExtensions);
const extensions = [...DEFAULT_EXTENSIONS, ...customCompilerExtensions];

function resolveModuleNames(moduleNames: string[], containingFile: string): Array<ts.ResolvedModuleFull | undefined> {
return moduleNames.map(moduleName => {
Expand Down Expand Up @@ -74,10 +73,11 @@ export function createCustomModuleResolver(
if (isBuiltin(sanitizedSpecifier) || isInNodeModules(name)) return undefined;

const resolvedFileName = resolveSync(sanitizedSpecifier, containingFile, extensions);

if (resolvedFileName) {
const ext = extname(resolvedFileName);

if (!virtualFileExtensions.includes(ext) && !FOREIGN_FILE_EXTENSIONS.has(ext)) {
if (!customCompilerExtensionsSet.has(ext)) {
const srcFilePath = toSourceFilePath(resolvedFileName);
if (srcFilePath) {
return {
Expand All @@ -91,12 +91,30 @@ export function createCustomModuleResolver(

return {
resolvedFileName,
extension: virtualFileExtensions.includes(ext) ? ts.Extension.Js : ext,
extension: customCompilerExtensionsSet.has(ext) ? ts.Extension.Js : ext,
isExternalLibraryImport: isInNodeModules(resolvedFileName),
resolvedUsingTsExtension: false,
};
}

const pathMappedFileName = tsMatchPath(
sanitizedSpecifier,
undefined,
undefined,
// Leave extensions empty and let `ts.resolveModuleName()` handle that.
// `tsMatchPath` will strip extensions from the returned specifier which
// means we don’t get the actual file path.
[]
);
if (pathMappedFileName) {
const ext = extname(pathMappedFileName);
return {
resolvedFileName: toPosix(pathMappedFileName),
extension: customCompilerExtensionsSet.has(ext) ? ts.Extension.Js : ext,
isExternalLibraryImport: false,
};
}

const tsResolvedModule = ts.resolveModuleName(
sanitizedSpecifier,
containingFile,
Expand All @@ -121,48 +139,9 @@ export function createCustomModuleResolver(
return tsResolvedModule;
}

const customResolvedModule = ts.resolveModuleName(
sanitizedSpecifier,
containingFile,
compilerOptions,
customSys
).resolvedModule;

if (customResolvedModule) {
if (isVirtualFilePath(customResolvedModule.resolvedFileName, virtualFileExtensions)) {
const resolvedFileName = ensureRealFilePath(customResolvedModule.resolvedFileName, virtualFileExtensions);

return {
extension: ts.Extension.Js,
resolvedFileName,
isExternalLibraryImport: customResolvedModule.isExternalLibraryImport,
};
}

return customResolvedModule;
}

const module = fileExists(sanitizedSpecifier, containingFile);
if (module) return module;

const resolvedPathMap = tsMatchPath(
sanitizedSpecifier,
undefined,
undefined,
// Leave extensions empty. When resolving "@foo/bar.ext",
// "@foo/bar.ext.js" will not be tried if "./foo/bar.ext" does not exist.
// This case has been handled by the resolvers above. This makes the
// resolution faster.
[]
);
if (resolvedPathMap) {
return {
resolvedFileName: resolvedPathMap,
extension: extname(resolvedPathMap),
isExternalLibraryImport: false,
};
}

return undefined;
}

Expand Down
29 changes: 0 additions & 29 deletions packages/knip/src/typescript/sys.ts

This file was deleted.

0 comments on commit d7325c6

Please sign in to comment.