diff --git a/lib/internal/modules/package_json_reader.js b/lib/internal/modules/package_json_reader.js index 9a9dcebb799c00..1deff520763f10 100644 --- a/lib/internal/modules/package_json_reader.js +++ b/lib/internal/modules/package_json_reader.js @@ -11,10 +11,15 @@ const modulesBinding = internalBinding('modules'); const { resolve, sep } = require('path'); const { kEmptyObject } = require('internal/util'); +/** + * @typedef {import('typings/internalBinding/modules').PackageConfig} PackageConfig + * @typedef {import('typings/internalBinding/modules').SerializedPackageConfig} SerializedPackageConfig + */ + /** * @param {string} path - * @param {import('typings/internalBinding/modules').SerializedPackageConfig} contents - * @returns {import('typings/internalBinding/modules').PackageConfig} + * @param {SerializedPackageConfig} contents + * @returns {PackageConfig} */ function deserializePackageJSON(path, contents) { if (contents === undefined) { @@ -75,7 +80,7 @@ function deserializePackageJSON(path, contents) { * specifier?: URL | string, * isESM?: boolean, * }} options - * @returns {import('typings/internalBinding/modules').PackageConfig} + * @returns {PackageConfig} */ function read(jsonPath, { base, specifier, isESM } = kEmptyObject) { // This function will be called by both CJS and ESM, so we need to make sure @@ -105,7 +110,7 @@ function readPackage(requestPath) { * 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. * @param {string} checkPath The path to start searching from. - * @returns {undefined | {data: import('typings/internalBinding/modules').PackageConfig, path: string}} + * @returns {undefined | {data: PackageConfig, path: string}} */ function getNearestParentPackageJSON(checkPath) { const result = modulesBinding.getNearestParentPackageJSON(checkPath); @@ -123,10 +128,19 @@ function getNearestParentPackageJSON(checkPath) { return { data, path }; } +/** + * Find the nearest package.json + * @param {URL['pathname']} origin Where to start searching. + * @returns {URL['pathname']} The fully resolved location of the package.json file. + */ +function findNearestPackageJSON(origin) { + return modulesBinding.findNearestPackageJSON(origin); +} + /** * Returns the package configuration for the given resolved URL. * @param {URL | string} resolved - The resolved URL. - * @returns {import('typings/internalBinding/modules').PackageConfig} - The package configuration. + * @returns {PackageConfig} - The package configuration. */ function getPackageScopeConfig(resolved) { const result = modulesBinding.getPackageScopeConfig(`${resolved}`); @@ -160,4 +174,5 @@ module.exports = { getNearestParentPackageJSON, getPackageScopeConfig, getPackageType, + findNearestPackageJSON, }; diff --git a/lib/module.js b/lib/module.js index 48ba9215b081eb..35519d78349707 100644 --- a/lib/module.js +++ b/lib/module.js @@ -10,6 +10,9 @@ const { flushCompileCache, getCompileCacheDir, } = require('internal/modules/helpers'); +const { + findNearestPackageJSON, +} = require('internal/modules/package_json_reader'); Module.findSourceMap = findSourceMap; Module.register = register; @@ -19,4 +22,5 @@ Module.enableCompileCache = enableCompileCache; Module.flushCompileCache = flushCompileCache; Module.getCompileCacheDir = getCompileCacheDir; +Module.findNearestPackageJSON = findNearestPackageJSON; module.exports = Module; diff --git a/src/node_modules.cc b/src/node_modules.cc index 157fa8d4442843..4fb01c75a656d7 100644 --- a/src/node_modules.cc +++ b/src/node_modules.cc @@ -313,8 +313,9 @@ const BindingData::PackageConfig* BindingData::TraverseParent( return nullptr; } -void BindingData::GetNearestParentPackageJSON( - const v8::FunctionCallbackInfo& args) { +void BindingData::FindNearestParentPackageJSON( + const v8::FunctionCallbackInfo& args +) { CHECK_GE(args.Length(), 1); CHECK(args[0]->IsString()); @@ -331,8 +332,15 @@ void BindingData::GetNearestParentPackageJSON( path_value_str.push_back(kPathSeparator); } - auto package_json = - TraverseParent(realm, std::filesystem::path(path_value_str)); + args.GetReturnValue().Set(path_value_str); +} + +void BindingData::GetNearestParentPackageJSON( + const v8::FunctionCallbackInfo& args +) { + auto path = FindNearestParentPackageJSON(args); + + auto package_json = TraverseParent(realm, std::filesystem::path(path_value_str)); if (package_json != nullptr) { args.GetReturnValue().Set(package_json->Serialize(realm)); @@ -340,32 +348,16 @@ void BindingData::GetNearestParentPackageJSON( } void BindingData::GetNearestParentPackageJSONType( - const FunctionCallbackInfo& 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); - } - - auto package_json = - TraverseParent(realm, std::filesystem::path(path_value_str)); + const FunctionCallbackInfo& args +) { + auto package_json = GetNearestParentPackageJSON(args); if (package_json == nullptr) { return; } - Local value = - ToV8Value(realm->context(), package_json->type).ToLocalChecked(); + Local value = ToV8Value(realm->context(), package_json->type).ToLocalChecked(); + args.GetReturnValue().Set(value); } @@ -497,6 +489,7 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data, SetMethod(isolate, target, "getPackageScopeConfig", GetPackageScopeConfig); SetMethod(isolate, target, "enableCompileCache", EnableCompileCache); SetMethod(isolate, target, "getCompileCacheDir", GetCompileCacheDir); + SetMethod(isolate, target, "findNearestPackageJSON", FindNearestParentPackageJSON); SetMethod(isolate, target, "flushCompileCache", FlushCompileCache); } diff --git a/typings/internalBinding/modules.d.ts b/typings/internalBinding/modules.d.ts index b9aa518abde337..6c07504b2535ec 100644 --- a/typings/internalBinding/modules.d.ts +++ b/typings/internalBinding/modules.d.ts @@ -23,4 +23,5 @@ export interface ModulesBinding { getNearestParentPackageJSONType(path: string): PackageConfig['type'] getPackageScopeConfig(path: string): SerializedPackageConfig | undefined getPackageJSONScripts(): string | undefined + findNearestPackageJSON(origin: URL['pathname']): URL['pathname'] | undefined }