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

Eliminiate custom TS System instance #680

Merged
merged 1 commit into from
Jun 16, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.

Loading