mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-20 13:45:34 -05:00
Support 'package.json' not in package root (#19133)
* Support 'package.json' not in package root * Test "foo/@bar" * More tests, and don't use "types" from the root package.json if not loading the root module
This commit is contained in:
@@ -77,16 +77,20 @@ namespace ts {
|
||||
traceEnabled: boolean;
|
||||
}
|
||||
|
||||
interface PackageJson {
|
||||
name?: string;
|
||||
version?: string;
|
||||
/** Just the fields that we use for module resolution. */
|
||||
interface PackageJsonPathFields {
|
||||
typings?: string;
|
||||
types?: string;
|
||||
main?: string;
|
||||
}
|
||||
|
||||
interface PackageJson extends PackageJsonPathFields {
|
||||
name?: string;
|
||||
version?: string;
|
||||
}
|
||||
|
||||
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
|
||||
function tryReadPackageJsonFields(readTypes: boolean, jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState): string | undefined {
|
||||
function tryReadPackageJsonFields(readTypes: boolean, jsonContent: PackageJsonPathFields, baseDirectory: string, state: ModuleResolutionState): string | undefined {
|
||||
return readTypes ? tryReadFromField("typings") || tryReadFromField("types") : tryReadFromField("main");
|
||||
|
||||
function tryReadFromField(fieldName: "typings" | "types" | "main"): string | undefined {
|
||||
@@ -886,7 +890,7 @@ namespace ts {
|
||||
return withPackageId(packageId, loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, packageJsonContent));
|
||||
}
|
||||
|
||||
function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, packageJsonContent: PackageJson | undefined): PathAndExtension | undefined {
|
||||
function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, packageJsonContent: PackageJsonPathFields | undefined): PathAndExtension | undefined {
|
||||
const fromPackageJson = packageJsonContent && loadModuleFromPackageJson(packageJsonContent, extensions, candidate, failedLookupLocations, state);
|
||||
if (fromPackageJson) {
|
||||
return fromPackageJson;
|
||||
@@ -901,7 +905,7 @@ namespace ts {
|
||||
failedLookupLocations: Push<string>,
|
||||
onlyRecordFailures: boolean,
|
||||
{ host, traceEnabled }: ModuleResolutionState,
|
||||
): { packageJsonContent: PackageJson | undefined, packageId: PackageId | undefined } {
|
||||
): { found: boolean, packageJsonContent: PackageJsonPathFields | undefined, packageId: PackageId | undefined } {
|
||||
const directoryExists = !onlyRecordFailures && directoryProbablyExists(nodeModuleDirectory, host);
|
||||
const packageJsonPath = pathToPackageJson(nodeModuleDirectory);
|
||||
if (directoryExists && host.fileExists(packageJsonPath)) {
|
||||
@@ -912,7 +916,7 @@ namespace ts {
|
||||
const packageId: PackageId = typeof packageJsonContent.name === "string" && typeof packageJsonContent.version === "string"
|
||||
? { name: packageJsonContent.name, subModuleName, version: packageJsonContent.version }
|
||||
: undefined;
|
||||
return { packageJsonContent, packageId };
|
||||
return { found: true, packageJsonContent, packageId };
|
||||
}
|
||||
else {
|
||||
if (directoryExists && traceEnabled) {
|
||||
@@ -920,11 +924,11 @@ namespace ts {
|
||||
}
|
||||
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
|
||||
failedLookupLocations.push(packageJsonPath);
|
||||
return { packageJsonContent: undefined, packageId: undefined };
|
||||
return { found: false, packageJsonContent: undefined, packageId: undefined };
|
||||
}
|
||||
}
|
||||
|
||||
function loadModuleFromPackageJson(jsonContent: PackageJson, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
function loadModuleFromPackageJson(jsonContent: PackageJsonPathFields, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
const file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript, jsonContent, candidate, state);
|
||||
if (!file) {
|
||||
return undefined;
|
||||
@@ -976,10 +980,22 @@ namespace ts {
|
||||
}
|
||||
|
||||
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
const { packageName, rest } = getPackageName(moduleName);
|
||||
const packageRootPath = combinePaths(nodeModulesFolder, packageName);
|
||||
const { packageJsonContent, packageId } = getPackageJsonInfo(packageRootPath, rest, failedLookupLocations, !nodeModulesFolderExists, state);
|
||||
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
|
||||
// First look for a nested package.json, as in `node_modules/foo/bar/package.json`.
|
||||
let packageJsonContent: PackageJsonPathFields | undefined;
|
||||
let packageId: PackageId | undefined;
|
||||
const packageInfo = getPackageJsonInfo(candidate, "", failedLookupLocations, /*onlyRecordFailures*/ !nodeModulesFolderExists, state);
|
||||
if (packageInfo.found) {
|
||||
({ packageJsonContent, packageId } = packageInfo);
|
||||
}
|
||||
else {
|
||||
const { packageName, rest } = getPackageName(moduleName);
|
||||
if (rest !== "") { // If "rest" is empty, we just did this search above.
|
||||
const packageRootPath = combinePaths(nodeModulesFolder, packageName);
|
||||
// Don't use a "types" or "main" from here because we're not loading the root, but a subdirectory -- just here for the packageId.
|
||||
packageId = getPackageJsonInfo(packageRootPath, rest, failedLookupLocations, !nodeModulesFolderExists, state).packageId;
|
||||
}
|
||||
}
|
||||
const pathAndExtension = loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
|
||||
loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state, packageJsonContent);
|
||||
return withPackageId(packageId, pathAndExtension);
|
||||
|
||||
Reference in New Issue
Block a user