Add auto-import for the package.json imports field (#55015)

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
Co-authored-by: Andrew Branch <andrew@wheream.io>
This commit is contained in:
Emma Hamilton
2023-12-21 09:48:03 -08:00
committed by GitHub
co-authored by Mateusz Burzyński Andrew Branch
parent 93e6b9da0c
commit fbcdb8cf4f
35 changed files with 2298 additions and 69 deletions
+1 -1
View File
@@ -50764,7 +50764,7 @@ export function signatureHasLiteralTypes(s: Signature) {
return !!(s.flags & SignatureFlags.HasLiteralTypes);
}
function createBasicNodeBuilderModuleSpecifierResolutionHost(host: TypeCheckerHost): ModuleSpecifierResolutionHost & { getCommonSourceDirectory(): string; } {
function createBasicNodeBuilderModuleSpecifierResolutionHost(host: TypeCheckerHost): ModuleSpecifierResolutionHost {
return {
getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory ? () => (host as Program).getCommonSourceDirectory() : () => "",
getCurrentDirectory: () => host.getCurrentDirectory(),
+10 -4
View File
@@ -2400,9 +2400,13 @@ function levenshteinWithMax(s1: string, s2: string, max: number): number | undef
}
/** @internal */
export function endsWith(str: string, suffix: string): boolean {
export function endsWith(str: string, suffix: string, ignoreCase?: boolean): boolean {
const expectedPos = str.length - suffix.length;
return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos;
return expectedPos >= 0 && (
ignoreCase
? equateStringsCaseInsensitive(str.slice(expectedPos), suffix)
: str.indexOf(suffix, expectedPos) === expectedPos
);
}
/** @internal */
@@ -2579,8 +2583,10 @@ export function findBestPatternMatch<T>(values: readonly T[], getPattern: (value
}
/** @internal */
export function startsWith(str: string, prefix: string): boolean {
return str.lastIndexOf(prefix, 0) === 0;
export function startsWith(str: string, prefix: string, ignoreCase?: boolean): boolean {
return ignoreCase
? equateStringsCaseInsensitive(str.slice(0, prefix.length), prefix)
: str.lastIndexOf(prefix, 0) === 0;
}
/** @internal */
+24 -9
View File
@@ -583,35 +583,50 @@ export function getOutputExtension(fileName: string, options: CompilerOptions):
Extension.Js;
}
function getOutputPathWithoutChangingExt(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, outputDir: string | undefined, getCommonSourceDirectory?: () => string) {
function getOutputPathWithoutChangingExt(
inputFileName: string,
ignoreCase: boolean,
outputDir: string | undefined,
getCommonSourceDirectory: () => string,
): string {
return outputDir ?
resolvePath(
outputDir,
getRelativePathFromDirectory(getCommonSourceDirectory ? getCommonSourceDirectory() : getCommonSourceDirectoryOfConfig(configFile, ignoreCase), inputFileName, ignoreCase),
getRelativePathFromDirectory(getCommonSourceDirectory(), inputFileName, ignoreCase),
) :
inputFileName;
}
/** @internal */
export function getOutputDeclarationFileName(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, getCommonSourceDirectory?: () => string) {
export function getOutputDeclarationFileName(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, getCommonSourceDirectory = () => getCommonSourceDirectoryOfConfig(configFile, ignoreCase)) {
return getOutputDeclarationFileNameWorker(inputFileName, configFile.options, ignoreCase, getCommonSourceDirectory);
}
/** @internal */
export function getOutputDeclarationFileNameWorker(inputFileName: string, options: CompilerOptions, ignoreCase: boolean, getCommonSourceDirectory: () => string) {
return changeExtension(
getOutputPathWithoutChangingExt(inputFileName, configFile, ignoreCase, configFile.options.declarationDir || configFile.options.outDir, getCommonSourceDirectory),
getOutputPathWithoutChangingExt(inputFileName, ignoreCase, options.declarationDir || options.outDir, getCommonSourceDirectory),
getDeclarationEmitExtensionForPath(inputFileName),
);
}
function getOutputJSFileName(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, getCommonSourceDirectory?: () => string) {
function getOutputJSFileName(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, getCommonSourceDirectory = () => getCommonSourceDirectoryOfConfig(configFile, ignoreCase)) {
if (configFile.options.emitDeclarationOnly) return undefined;
const isJsonFile = fileExtensionIs(inputFileName, Extension.Json);
const outputFileName = changeExtension(
getOutputPathWithoutChangingExt(inputFileName, configFile, ignoreCase, configFile.options.outDir, getCommonSourceDirectory),
getOutputExtension(inputFileName, configFile.options),
);
const outputFileName = getOutputJSFileNameWorker(inputFileName, configFile.options, ignoreCase, getCommonSourceDirectory);
return !isJsonFile || comparePaths(inputFileName, outputFileName, Debug.checkDefined(configFile.options.configFilePath), ignoreCase) !== Comparison.EqualTo ?
outputFileName :
undefined;
}
/** @internal */
export function getOutputJSFileNameWorker(inputFileName: string, options: CompilerOptions, ignoreCase: boolean, getCommonSourceDirectory: () => string): string {
return changeExtension(
getOutputPathWithoutChangingExt(inputFileName, ignoreCase, options.outDir, getCommonSourceDirectory),
getOutputExtension(inputFileName, options),
);
}
function createAddOutput() {
let outputs: string[] | undefined;
return { addOutput, getOutputs };
+5
View File
@@ -915,6 +915,11 @@ export function isPackageJsonInfo(entry: PackageJsonInfoCacheEntry | undefined):
return !!(entry as PackageJsonInfo | undefined)?.contents;
}
/** @internal */
export function isMissingPackageJsonInfo(entry: PackageJsonInfoCacheEntry | undefined): entry is MissingPackageJsonInfo {
return !!entry && !(entry as PackageJsonInfo).contents;
}
export interface PackageJsonInfoCache {
/** @internal */ getPackageJsonInfo(packageJsonPath: string): PackageJsonInfoCacheEntry | undefined;
/** @internal */ setPackageJsonInfo(packageJsonPath: string, info: PackageJsonInfoCacheEntry): void;
+113 -46
View File
@@ -42,6 +42,8 @@ import {
getModuleSpecifierEndingPreference,
getNodeModulePathParts,
getNormalizedAbsolutePath,
getOutputDeclarationFileNameWorker,
getOutputJSFileNameWorker,
getOwnKeys,
getPackageJsonTypesVersionsPaths,
getPackageNameFromTypesPackageName,
@@ -49,18 +51,21 @@ import {
getRelativePathFromDirectory,
getRelativePathToDirectoryOrUrl,
getResolvePackageJsonExports,
getResolvePackageJsonImports,
getSourceFileOfModule,
getSupportedExtensions,
getTextOfIdentifierOrLiteral,
hasJSFileExtension,
hasTSFileExtension,
hostGetCanonicalFileName,
hostUsesCaseSensitiveFileNames,
Identifier,
isAmbientModule,
isApplicableVersionedTypesKey,
isDeclarationFileName,
isExternalModuleAugmentation,
isExternalModuleNameRelative,
isMissingPackageJsonInfo,
isModuleBlock,
isModuleDeclaration,
isNonGlobalAmbientModule,
@@ -107,6 +112,7 @@ import {
SymbolFlags,
toPath,
tryGetExtensionFromPath,
tryParseJson,
tryParsePatterns,
TypeChecker,
UserPreferences,
@@ -485,7 +491,7 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt
const allowedEndings = getAllowedEndingsInPrefererredOrder(importMode);
const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName, allowedEndings, compilerOptions) ||
processEnding(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), allowedEndings, compilerOptions);
if (!baseUrl && !paths || relativePreference === RelativePreference.Relative) {
if (!baseUrl && !paths && !getResolvePackageJsonImports(compilerOptions) || relativePreference === RelativePreference.Relative) {
return pathsOnly ? undefined : relativePath;
}
@@ -495,12 +501,14 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt
return pathsOnly ? undefined : relativePath;
}
const fromPaths = paths && tryGetModuleNameFromPaths(relativeToBaseUrl, paths, allowedEndings, host, compilerOptions);
const fromPackageJsonImports = pathsOnly ? undefined : tryGetModuleNameFromPackageJsonImports(moduleFileName, sourceDirectory, compilerOptions, host, importMode);
const fromPaths = pathsOnly || fromPackageJsonImports === undefined ? paths && tryGetModuleNameFromPaths(relativeToBaseUrl, paths, allowedEndings, host, compilerOptions) : undefined;
if (pathsOnly) {
return fromPaths;
}
const maybeNonRelative = fromPaths === undefined && baseUrl !== undefined ? processEnding(relativeToBaseUrl, allowedEndings, compilerOptions) : fromPaths;
const maybeNonRelative = fromPackageJsonImports ?? (fromPaths === undefined && baseUrl !== undefined ? processEnding(relativeToBaseUrl, allowedEndings, compilerOptions) : fromPaths);
if (!maybeNonRelative) {
return relativePath;
}
@@ -567,8 +575,8 @@ function getNearestAncestorDirectoryWithPackageJson(host: ModuleSpecifierResolut
if (host.getNearestAncestorDirectoryWithPackageJson) {
return host.getNearestAncestorDirectoryWithPackageJson(fileName);
}
return !!forEachAncestorDirectory(fileName, directory => {
return host.fileExists(combinePaths(directory, "package.json")) ? true : undefined;
return forEachAncestorDirectory(fileName, directory => {
return host.fileExists(combinePaths(directory, "package.json")) ? directory : undefined;
});
}
@@ -843,64 +851,79 @@ const enum MatchingMode {
Pattern,
}
function tryGetModuleNameFromExports(options: CompilerOptions, targetFilePath: string, packageDirectory: string, packageName: string, exports: unknown, conditions: string[], mode = MatchingMode.Exact): { moduleFileToTry: string; } | undefined {
function tryGetModuleNameFromExportsOrImports(options: CompilerOptions, host: ModuleSpecifierResolutionHost, targetFilePath: string, packageDirectory: string, packageName: string, exports: unknown, conditions: string[], mode: MatchingMode, isImports: boolean): { moduleFileToTry: string; } | undefined {
if (typeof exports === "string") {
const ignoreCase = !hostUsesCaseSensitiveFileNames(host);
const getCommonSourceDirectory = () => host.getCommonSourceDirectory();
const outputFile = isImports && getOutputJSFileNameWorker(targetFilePath, options, ignoreCase, getCommonSourceDirectory);
const declarationFile = isImports && getOutputDeclarationFileNameWorker(targetFilePath, options, ignoreCase, getCommonSourceDirectory);
const pathOrPattern = getNormalizedAbsolutePath(combinePaths(packageDirectory, exports), /*currentDirectory*/ undefined);
const extensionSwappedTarget = hasTSFileExtension(targetFilePath) ? removeFileExtension(targetFilePath) + tryGetJSExtensionForFile(targetFilePath, options) : undefined;
switch (mode) {
case MatchingMode.Exact:
if (comparePaths(targetFilePath, pathOrPattern) === Comparison.EqualTo || (extensionSwappedTarget && comparePaths(extensionSwappedTarget, pathOrPattern) === Comparison.EqualTo)) {
if (
extensionSwappedTarget && comparePaths(extensionSwappedTarget, pathOrPattern, ignoreCase) === Comparison.EqualTo ||
comparePaths(targetFilePath, pathOrPattern, ignoreCase) === Comparison.EqualTo ||
outputFile && comparePaths(outputFile, pathOrPattern, ignoreCase) === Comparison.EqualTo ||
declarationFile && comparePaths(declarationFile, pathOrPattern, ignoreCase) === Comparison.EqualTo
) {
return { moduleFileToTry: packageName };
}
break;
case MatchingMode.Directory:
if (containsPath(pathOrPattern, targetFilePath)) {
if (extensionSwappedTarget && containsPath(pathOrPattern, extensionSwappedTarget, ignoreCase)) {
const fragment = getRelativePathFromDirectory(pathOrPattern, extensionSwappedTarget, /*ignoreCase*/ false);
return { moduleFileToTry: getNormalizedAbsolutePath(combinePaths(combinePaths(packageName, exports), fragment), /*currentDirectory*/ undefined) };
}
if (containsPath(pathOrPattern, targetFilePath, ignoreCase)) {
const fragment = getRelativePathFromDirectory(pathOrPattern, targetFilePath, /*ignoreCase*/ false);
return { moduleFileToTry: getNormalizedAbsolutePath(combinePaths(combinePaths(packageName, exports), fragment), /*currentDirectory*/ undefined) };
}
if (outputFile && containsPath(pathOrPattern, outputFile, ignoreCase)) {
const fragment = getRelativePathFromDirectory(pathOrPattern, outputFile, /*ignoreCase*/ false);
return { moduleFileToTry: combinePaths(packageName, fragment) };
}
if (declarationFile && containsPath(pathOrPattern, declarationFile, ignoreCase)) {
const fragment = getRelativePathFromDirectory(pathOrPattern, declarationFile, /*ignoreCase*/ false);
return { moduleFileToTry: combinePaths(packageName, fragment) };
}
break;
case MatchingMode.Pattern:
const starPos = pathOrPattern.indexOf("*");
const leadingSlice = pathOrPattern.slice(0, starPos);
const trailingSlice = pathOrPattern.slice(starPos + 1);
if (startsWith(targetFilePath, leadingSlice) && endsWith(targetFilePath, trailingSlice)) {
if (extensionSwappedTarget && startsWith(extensionSwappedTarget, leadingSlice, ignoreCase) && endsWith(extensionSwappedTarget, trailingSlice, ignoreCase)) {
const starReplacement = extensionSwappedTarget.slice(leadingSlice.length, extensionSwappedTarget.length - trailingSlice.length);
return { moduleFileToTry: replaceFirstStar(packageName, starReplacement) };
}
if (startsWith(targetFilePath, leadingSlice, ignoreCase) && endsWith(targetFilePath, trailingSlice, ignoreCase)) {
const starReplacement = targetFilePath.slice(leadingSlice.length, targetFilePath.length - trailingSlice.length);
return { moduleFileToTry: replaceFirstStar(packageName, starReplacement) };
}
if (extensionSwappedTarget && startsWith(extensionSwappedTarget, leadingSlice) && endsWith(extensionSwappedTarget, trailingSlice)) {
const starReplacement = extensionSwappedTarget.slice(leadingSlice.length, extensionSwappedTarget.length - trailingSlice.length);
if (outputFile && startsWith(outputFile, leadingSlice, ignoreCase) && endsWith(outputFile, trailingSlice, ignoreCase)) {
const starReplacement = outputFile.slice(leadingSlice.length, outputFile.length - trailingSlice.length);
return { moduleFileToTry: replaceFirstStar(packageName, starReplacement) };
}
if (declarationFile && startsWith(declarationFile, leadingSlice, ignoreCase) && endsWith(declarationFile, trailingSlice, ignoreCase)) {
const starReplacement = declarationFile.slice(leadingSlice.length, declarationFile.length - trailingSlice.length);
return { moduleFileToTry: replaceFirstStar(packageName, starReplacement) };
}
break;
}
}
else if (Array.isArray(exports)) {
return forEach(exports, e => tryGetModuleNameFromExports(options, targetFilePath, packageDirectory, packageName, e, conditions));
return forEach(exports, e => tryGetModuleNameFromExportsOrImports(options, host, targetFilePath, packageDirectory, packageName, e, conditions, mode, isImports));
}
else if (typeof exports === "object" && exports !== null) { // eslint-disable-line no-null/no-null
if (allKeysStartWithDot(exports as MapLike<unknown>)) {
// sub-mappings
// 3 cases:
// * directory mappings (legacyish, key ends with / (technically allows index/extension resolution under cjs mode))
// * pattern mappings (contains a *)
// * exact mappings (no *, does not end with /)
return forEach(getOwnKeys(exports as MapLike<unknown>), k => {
const subPackageName = getNormalizedAbsolutePath(combinePaths(packageName, k), /*currentDirectory*/ undefined);
const mode = endsWith(k, "/") ? MatchingMode.Directory
: k.includes("*") ? MatchingMode.Pattern
: MatchingMode.Exact;
return tryGetModuleNameFromExports(options, targetFilePath, packageDirectory, subPackageName, (exports as MapLike<unknown>)[k], conditions, mode);
});
}
else {
// conditional mapping
for (const key of getOwnKeys(exports as MapLike<unknown>)) {
if (key === "default" || conditions.includes(key) || isApplicableVersionedTypesKey(conditions, key)) {
const subTarget = (exports as MapLike<unknown>)[key];
const result = tryGetModuleNameFromExports(options, targetFilePath, packageDirectory, packageName, subTarget, conditions, mode);
if (result) {
return result;
}
// conditional mapping
for (const key of getOwnKeys(exports as MapLike<unknown>)) {
if (key === "default" || conditions.indexOf(key) >= 0 || isApplicableVersionedTypesKey(conditions, key)) {
const subTarget = (exports as MapLike<unknown>)[key];
const result = tryGetModuleNameFromExportsOrImports(options, host, targetFilePath, packageDirectory, packageName, subTarget, conditions, mode, isImports);
if (result) {
return result;
}
}
}
@@ -908,6 +931,53 @@ function tryGetModuleNameFromExports(options: CompilerOptions, targetFilePath: s
return undefined;
}
function tryGetModuleNameFromExports(options: CompilerOptions, host: ModuleSpecifierResolutionHost, targetFilePath: string, packageDirectory: string, packageName: string, exports: unknown, conditions: string[]): { moduleFileToTry: string; } | undefined {
if (typeof exports === "object" && exports !== null && !Array.isArray(exports) && allKeysStartWithDot(exports as MapLike<unknown>)) { // eslint-disable-line no-null/no-null
// sub-mappings
// 3 cases:
// * directory mappings (legacyish, key ends with / (technically allows index/extension resolution under cjs mode))
// * pattern mappings (contains a *)
// * exact mappings (no *, does not end with /)
return forEach(getOwnKeys(exports as MapLike<unknown>), k => {
const subPackageName = getNormalizedAbsolutePath(combinePaths(packageName, k), /*currentDirectory*/ undefined);
const mode = endsWith(k, "/") ? MatchingMode.Directory
: k.includes("*") ? MatchingMode.Pattern
: MatchingMode.Exact;
return tryGetModuleNameFromExportsOrImports(options, host, targetFilePath, packageDirectory, subPackageName, (exports as MapLike<unknown>)[k], conditions, mode, /*isImports*/ false);
});
}
return tryGetModuleNameFromExportsOrImports(options, host, targetFilePath, packageDirectory, packageName, exports, conditions, MatchingMode.Exact, /*isImports*/ false);
}
function tryGetModuleNameFromPackageJsonImports(moduleFileName: string, sourceDirectory: string, options: CompilerOptions, host: ModuleSpecifierResolutionHost, importMode: ResolutionMode) {
if (!host.readFile || !getResolvePackageJsonImports(options)) {
return undefined;
}
const ancestorDirectoryWithPackageJson = getNearestAncestorDirectoryWithPackageJson(host, sourceDirectory);
if (!ancestorDirectoryWithPackageJson) {
return undefined;
}
const packageJsonPath = combinePaths(ancestorDirectoryWithPackageJson, "package.json");
const cachedPackageJson = host.getPackageJsonInfoCache?.()?.getPackageJsonInfo(packageJsonPath);
if (isMissingPackageJsonInfo(cachedPackageJson) || !host.fileExists(packageJsonPath)) {
return undefined;
}
const packageJsonContent = cachedPackageJson?.contents.packageJsonContent || tryParseJson(host.readFile(packageJsonPath)!);
const imports = packageJsonContent?.imports;
if (!imports) {
return undefined;
}
const conditions = getConditions(options, importMode);
return forEach(getOwnKeys(imports as MapLike<unknown>), k => {
if (!startsWith(k, "#") || k === "#" || startsWith(k, "#/")) return undefined;
const mode = endsWith(k, "/") ? MatchingMode.Directory
: k.includes("*") ? MatchingMode.Pattern
: MatchingMode.Exact;
return tryGetModuleNameFromExportsOrImports(options, host, moduleFileName, ancestorDirectoryWithPackageJson, k, (imports as MapLike<unknown>)[k], conditions, mode, /*isImports*/ true);
})?.moduleFileToTry;
}
function tryGetModuleNameFromRootDirs(rootDirs: readonly string[], moduleFileName: string, sourceDirectory: string, getCanonicalFileName: (file: string) => string, allowedEndings: readonly ModuleSpecifierEnding[], compilerOptions: CompilerOptions): string | undefined {
const normalizedTargetPaths = getPathsRelativeToRootDirs(moduleFileName, rootDirs, getCanonicalFileName);
if (normalizedTargetPaths === undefined) {
@@ -995,7 +1065,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
let maybeBlockedByTypesVersions = false;
const cachedPackageJson = host.getPackageJsonInfoCache?.()?.getPackageJsonInfo(packageJsonPath);
if (isPackageJsonInfo(cachedPackageJson) || cachedPackageJson === undefined && host.fileExists(packageJsonPath)) {
const packageJsonContent = cachedPackageJson?.contents.packageJsonContent || JSON.parse(host.readFile!(packageJsonPath)!);
const packageJsonContent: Record<string, any> | undefined = cachedPackageJson?.contents.packageJsonContent || tryParseJson(host.readFile!(packageJsonPath)!);
const importMode = overrideMode || importingSourceFile.impliedNodeFormat;
if (getResolvePackageJsonExports(options)) {
// The package name that we found in node_modules could be different from the package
@@ -1004,20 +1074,17 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
const nodeModulesDirectoryName = packageRootPath.substring(parts.topLevelPackageNameIndex + 1);
const packageName = getPackageNameFromTypesPackageName(nodeModulesDirectoryName);
const conditions = getConditions(options, importMode);
const fromExports = packageJsonContent.exports
? tryGetModuleNameFromExports(options, path, packageRootPath, packageName, packageJsonContent.exports, conditions)
const fromExports = packageJsonContent?.exports
? tryGetModuleNameFromExports(options, host, path, packageRootPath, packageName, packageJsonContent.exports, conditions)
: undefined;
if (fromExports) {
const withJsExtension = !hasTSFileExtension(fromExports.moduleFileToTry)
? fromExports
: { moduleFileToTry: removeFileExtension(fromExports.moduleFileToTry) + tryGetJSExtensionForFile(fromExports.moduleFileToTry, options) };
return { ...withJsExtension, verbatimFromExports: true };
return { ...fromExports, verbatimFromExports: true };
}
if (packageJsonContent.exports) {
if (packageJsonContent?.exports) {
return { moduleFileToTry: path, blockedByExports: true };
}
}
const versionPaths = packageJsonContent.typesVersions
const versionPaths = packageJsonContent?.typesVersions
? getPackageJsonTypesVersionsPaths(packageJsonContent.typesVersions)
: undefined;
if (versionPaths) {
@@ -1037,7 +1104,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
}
}
// If the file is the main module, it can be imported by the package name
const mainFileRelative = packageJsonContent.typings || packageJsonContent.types || packageJsonContent.main || "index.js";
const mainFileRelative = packageJsonContent?.typings || packageJsonContent?.types || packageJsonContent?.main || "index.js";
if (isString(mainFileRelative) && !(maybeBlockedByTypesVersions && matchPatternOrExact(tryParsePatterns(versionPaths!.paths), mainFileRelative))) {
// The 'main' file is also subject to mapping through typesVersions, and we couldn't come up with a path
// explicitly through typesVersions, so if it matches a key in typesVersions now, it's not reachable.
@@ -1052,7 +1119,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
return { packageRootPath, moduleFileToTry };
}
else if (
packageJsonContent.type !== "module" &&
packageJsonContent?.type !== "module" &&
!fileExtensionIsOneOf(canonicalModuleFileToTry, extensionsNotSupportingExtensionlessResolution) &&
startsWith(canonicalModuleFileToTry, mainExportFile) &&
getDirectoryPath(canonicalModuleFileToTry) === removeTrailingDirectorySeparator(mainExportFile) &&
+1
View File
@@ -9690,6 +9690,7 @@ export interface ModuleSpecifierResolutionHost {
getProjectReferenceRedirect(fileName: string): string | undefined;
isSourceOfProjectReferenceRedirect(fileName: string): boolean;
getFileIncludeReasons(): MultiMap<Path, FileIncludeReason>;
getCommonSourceDirectory(): string;
}
/** @internal */
+10
View File
@@ -7484,6 +7484,16 @@ export function readJson(path: string, host: { readFile(fileName: string): strin
return readJsonOrUndefined(path, host) || {};
}
/** @internal */
export function tryParseJson(text: string) {
try {
return JSON.parse(text);
}
catch {
return undefined;
}
}
/** @internal */
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean; }): boolean {
// if host does not support 'directoryExists' assume that directory will exist
+2 -9
View File
@@ -362,6 +362,7 @@ import {
tokenToString,
toPath,
tryCast,
tryParseJson,
Type,
TypeChecker,
TypeFlags,
@@ -2473,6 +2474,7 @@ export function createModuleSpecifierResolutionHost(program: Program, host: Lang
isSourceOfProjectReferenceRedirect: fileName => program.isSourceOfProjectReferenceRedirect(fileName),
getNearestAncestorDirectoryWithPackageJson: maybeBind(host, host.getNearestAncestorDirectoryWithPackageJson),
getFileIncludeReasons: () => program.getFileIncludeReasons(),
getCommonSourceDirectory: () => program.getCommonSourceDirectory(),
};
}
@@ -3895,15 +3897,6 @@ export function createPackageJsonImportFilter(fromFile: SourceFile, preferences:
}
}
function tryParseJson(text: string) {
try {
return JSON.parse(text);
}
catch {
return undefined;
}
}
/** @internal */
export function consumesNodeCoreModules(sourceFile: SourceFile): boolean {
return some(sourceFile.imports, ({ text }) => JsTyping.nodeCoreModules.has(text));