mirror of
https://github.com/nodejs/node.git
synced 2025-12-27 23:41:14 +00:00
src: reduce the nearest parent package JSON cache size
PR-URL: https://github.com/nodejs/node/pull/59888 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
This commit is contained in:
parent
db926dc1fc
commit
e596098e50
@ -6,7 +6,9 @@ const {
|
||||
ObjectDefineProperty,
|
||||
RegExpPrototypeExec,
|
||||
SafeMap,
|
||||
StringPrototypeEndsWith,
|
||||
StringPrototypeIndexOf,
|
||||
StringPrototypeLastIndexOf,
|
||||
StringPrototypeSlice,
|
||||
} = primordials;
|
||||
const {
|
||||
@ -26,6 +28,7 @@ const {
|
||||
const { kEmptyObject } = require('internal/util');
|
||||
const modulesBinding = internalBinding('modules');
|
||||
const path = require('path');
|
||||
const permission = require('internal/process/permission');
|
||||
const { validateString } = require('internal/validators');
|
||||
const internalFsBinding = internalBinding('fs');
|
||||
|
||||
@ -127,6 +130,45 @@ function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a file path, walk the filesystem upwards until we find its closest parent
|
||||
* `package.json` file, stopping when:
|
||||
* 1. we find a `package.json` file;
|
||||
* 2. we find a path that we do not have permission to read;
|
||||
* 3. we find a containing `node_modules` directory;
|
||||
* 4. or, we reach the filesystem root
|
||||
* @returns {undefined | string}
|
||||
*/
|
||||
function findParentPackageJSON(checkPath) {
|
||||
const enabledPermission = permission.isEnabled();
|
||||
|
||||
const rootSeparatorIndex = StringPrototypeIndexOf(checkPath, path.sep);
|
||||
let separatorIndex;
|
||||
|
||||
do {
|
||||
separatorIndex = StringPrototypeLastIndexOf(checkPath, path.sep);
|
||||
checkPath = StringPrototypeSlice(checkPath, 0, separatorIndex);
|
||||
|
||||
if (enabledPermission && !permission.has('fs.read', checkPath + path.sep)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (StringPrototypeEndsWith(checkPath, path.sep + 'node_modules')) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const maybePackageJSONPath = checkPath + path.sep + 'package.json';
|
||||
const stat = internalFsBinding.internalModuleStat(checkPath + path.sep + 'package.json');
|
||||
|
||||
const packageJSONExists = stat === 0;
|
||||
if (packageJSONExists) {
|
||||
return maybePackageJSONPath;
|
||||
}
|
||||
} while (separatorIndex > rootSeparatorIndex);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the nearest parent package.json file from a given path.
|
||||
* Return the package.json data and the path to the package.json file, or undefined.
|
||||
@ -134,11 +176,17 @@ function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
|
||||
* @returns {undefined | DeserializedPackageConfig}
|
||||
*/
|
||||
function getNearestParentPackageJSON(checkPath) {
|
||||
if (nearestParentPackageJSONCache.has(checkPath)) {
|
||||
return nearestParentPackageJSONCache.get(checkPath);
|
||||
const nearestParentPackageJSON = findParentPackageJSON(checkPath);
|
||||
|
||||
if (nearestParentPackageJSON === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = modulesBinding.getNearestParentPackageJSON(checkPath);
|
||||
if (nearestParentPackageJSONCache.has(nearestParentPackageJSON)) {
|
||||
return nearestParentPackageJSONCache.get(nearestParentPackageJSON);
|
||||
}
|
||||
|
||||
const result = modulesBinding.readPackageJSON(nearestParentPackageJSON);
|
||||
|
||||
if (result === undefined) {
|
||||
nearestParentPackageJSONCache.set(checkPath, undefined);
|
||||
@ -146,7 +194,7 @@ function getNearestParentPackageJSON(checkPath) {
|
||||
}
|
||||
|
||||
const packageConfig = deserializePackageJSON(checkPath, result);
|
||||
nearestParentPackageJSONCache.set(checkPath, packageConfig);
|
||||
nearestParentPackageJSONCache.set(nearestParentPackageJSON, packageConfig);
|
||||
|
||||
return packageConfig;
|
||||
}
|
||||
|
||||
@ -320,40 +320,6 @@ const BindingData::PackageConfig* BindingData::TraverseParent(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BindingData::GetNearestParentPackageJSON(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
CHECK_GE(args.Length(), 1);
|
||||
CHECK(args[0]->IsString());
|
||||
|
||||
Realm* realm = Realm::GetCurrent(args);
|
||||
BufferValue path_value(realm->isolate(), args[0]);
|
||||
// Check if the path has a trailing slash. If so, add it after
|
||||
// ToNamespacedPath() as it will be deleted by ToNamespacedPath()
|
||||
bool slashCheck = path_value.ToStringView().ends_with(kPathSeparator);
|
||||
|
||||
ToNamespacedPath(realm->env(), &path_value);
|
||||
|
||||
std::string path_value_str = path_value.ToString();
|
||||
if (slashCheck) {
|
||||
path_value_str.push_back(kPathSeparator);
|
||||
}
|
||||
|
||||
std::filesystem::path path;
|
||||
|
||||
#ifdef _WIN32
|
||||
std::wstring wide_path = ConvertToWideString(path_value_str, GetACP());
|
||||
path = std::filesystem::path(wide_path);
|
||||
#else
|
||||
path = std::filesystem::path(path_value_str);
|
||||
#endif
|
||||
|
||||
auto package_json = TraverseParent(realm, path);
|
||||
|
||||
if (package_json != nullptr) {
|
||||
args.GetReturnValue().Set(package_json->Serialize(realm));
|
||||
}
|
||||
}
|
||||
|
||||
void BindingData::GetNearestParentPackageJSONType(
|
||||
const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK_GE(args.Length(), 1);
|
||||
@ -680,10 +646,6 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||
target,
|
||||
"getNearestParentPackageJSONType",
|
||||
GetNearestParentPackageJSONType);
|
||||
SetMethod(isolate,
|
||||
target,
|
||||
"getNearestParentPackageJSON",
|
||||
GetNearestParentPackageJSON);
|
||||
SetMethod(
|
||||
isolate, target, "getPackageScopeConfig", GetPackageScopeConfig<false>);
|
||||
SetMethod(isolate, target, "getPackageType", GetPackageScopeConfig<true>);
|
||||
@ -740,7 +702,6 @@ void BindingData::RegisterExternalReferences(
|
||||
ExternalReferenceRegistry* registry) {
|
||||
registry->Register(ReadPackageJSON);
|
||||
registry->Register(GetNearestParentPackageJSONType);
|
||||
registry->Register(GetNearestParentPackageJSON);
|
||||
registry->Register(GetPackageScopeConfig<false>);
|
||||
registry->Register(GetPackageScopeConfig<true>);
|
||||
registry->Register(EnableCompileCache);
|
||||
|
||||
@ -55,8 +55,6 @@ class BindingData : public SnapshotableObject {
|
||||
SET_MEMORY_INFO_NAME(BindingData)
|
||||
|
||||
static void ReadPackageJSON(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void GetNearestParentPackageJSON(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void GetNearestParentPackageJSONType(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
template <bool return_only_type>
|
||||
|
||||
1
typings/internalBinding/modules.d.ts
vendored
1
typings/internalBinding/modules.d.ts
vendored
@ -23,7 +23,6 @@ export type SerializedPackageConfig = [
|
||||
export interface ModulesBinding {
|
||||
readPackageJSON(path: string): SerializedPackageConfig | undefined;
|
||||
getNearestParentPackageJSONType(path: string): PackageConfig['type']
|
||||
getNearestParentPackageJSON(path: string): SerializedPackageConfig | undefined
|
||||
getPackageScopeConfig(path: string): SerializedPackageConfig | undefined
|
||||
getPackageType(path: string): PackageConfig['type'] | undefined
|
||||
enableCompileCache(path?: string): { status: number, message?: string, directory?: string }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user