Skip to content

Commit 70dd5f8

Browse files
module: add findNearestPackageJSON utility
1 parent 4062b3f commit 70dd5f8

File tree

4 files changed

+58
-35
lines changed

4 files changed

+58
-35
lines changed

lib/internal/modules/package_json_reader.js

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,19 @@ const modulesBinding = internalBinding('modules');
1111
const { resolve, sep } = require('path');
1212
const { kEmptyObject } = require('internal/util');
1313

14+
/**
15+
* @typedef {import('typings/internalBinding/modules').FullPackageConfig} FullPackageConfig
16+
* @typedef {import('typings/internalBinding/modules').PackageConfig} PackageConfig
17+
* @typedef {import('typings/internalBinding/modules').SerializedPackageConfig} SerializedPackageConfig
18+
*/
19+
1420
/**
1521
* @param {string} path
16-
* @param {import('typings/internalBinding/modules').SerializedPackageConfig} contents
17-
* @returns {import('typings/internalBinding/modules').PackageConfig}
22+
* @param {SerializedPackageConfig} contents
23+
* @param {boolean} everything
24+
* @returns {everything extends true ? FullPackageConfig : PackageConfig}
1825
*/
19-
function deserializePackageJSON(path, contents) {
26+
function deserializePackageJSON(path, contents, everything = false) {
2027
if (contents === undefined) {
2128
return {
2229
__proto__: null,
@@ -64,6 +71,7 @@ function deserializePackageJSON(path, contents) {
6471
ObjectDefineProperty(this, 'exports', { __proto__: null, value });
6572
return this.exports;
6673
},
74+
...(everything && contents[6]),
6775
};
6876
}
6977

@@ -75,7 +83,7 @@ function deserializePackageJSON(path, contents) {
7583
* specifier?: URL | string,
7684
* isESM?: boolean,
7785
* }} options
78-
* @returns {import('typings/internalBinding/modules').PackageConfig}
86+
* @returns {PackageConfig}
7987
*/
8088
function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
8189
// This function will be called by both CJS and ESM, so we need to make sure
@@ -105,16 +113,17 @@ function readPackage(requestPath) {
105113
* Get the nearest parent package.json file from a given path.
106114
* Return the package.json data and the path to the package.json file, or undefined.
107115
* @param {string} checkPath The path to start searching from.
108-
* @returns {undefined | {data: import('typings/internalBinding/modules').PackageConfig, path: string}}
116+
* @param {boolean} everything Whether to include unrecognised fields.
117+
* @returns {undefined | {data: PackageConfig, path: string}}
109118
*/
110-
function getNearestParentPackageJSON(checkPath) {
119+
function getNearestParentPackageJSON(checkPath, everything = false) {
111120
const result = modulesBinding.getNearestParentPackageJSON(checkPath);
112121

113122
if (result === undefined) {
114123
return undefined;
115124
}
116125

117-
const data = deserializePackageJSON(checkPath, result);
126+
const data = deserializePackageJSON(checkPath, result, everything);
118127

119128
// Path should be the root folder of the matched package.json
120129
// For example for ~/path/package.json, it should be ~/path
@@ -123,16 +132,26 @@ function getNearestParentPackageJSON(checkPath) {
123132
return { data, path };
124133
}
125134

135+
/**
136+
* Find the nearest package.json
137+
* @param {URL['pathname']} origin Where to start searching.
138+
* @returns {URL['pathname']} The fully resolved location of the package.json file.
139+
*/
140+
function findNearestPackageJSON(origin) {
141+
return modulesBinding.findNearestPackageJSON(origin);
142+
}
143+
126144
/**
127145
* Returns the package configuration for the given resolved URL.
128146
* @param {URL | string} resolved - The resolved URL.
129-
* @returns {import('typings/internalBinding/modules').PackageConfig} - The package configuration.
147+
* @param {boolean} everything - Whether to include unrecognised fields.
148+
* @returns {PackageConfig} - The package configuration.
130149
*/
131-
function getPackageScopeConfig(resolved) {
150+
function getPackageScopeConfig(resolved, everything = false) {
132151
const result = modulesBinding.getPackageScopeConfig(`${resolved}`);
133152

134153
if (ArrayIsArray(result)) {
135-
return deserializePackageJSON(`${resolved}`, result);
154+
return deserializePackageJSON(`${resolved}`, result, everything);
136155
}
137156

138157
// This means that the response is a string
@@ -160,4 +179,5 @@ module.exports = {
160179
getNearestParentPackageJSON,
161180
getPackageScopeConfig,
162181
getPackageType,
182+
findNearestPackageJSON,
163183
};

lib/module.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ const {
1010
flushCompileCache,
1111
getCompileCacheDir,
1212
} = require('internal/modules/helpers');
13+
const {
14+
getPackageScopeConfig,
15+
findNearestPackageJSON,
16+
} = require('internal/modules/package_json_reader');
1317

1418
Module.findSourceMap = findSourceMap;
1519
Module.register = register;
@@ -19,4 +23,6 @@ Module.enableCompileCache = enableCompileCache;
1923
Module.flushCompileCache = flushCompileCache;
2024

2125
Module.getCompileCacheDir = getCompileCacheDir;
26+
Module.getPackageScopeConfig = getPackageScopeConfig;
27+
Module.findNearestPackageJSON = findNearestPackageJSON;
2228
module.exports = Module;

src/node_modules.cc

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,9 @@ const BindingData::PackageConfig* BindingData::TraverseParent(
313313
return nullptr;
314314
}
315315

316-
void BindingData::GetNearestParentPackageJSON(
317-
const v8::FunctionCallbackInfo<v8::Value>& args) {
316+
void BindingData::FindNearestParentPackageJSON(
317+
const v8::FunctionCallbackInfo<v8::Value>& args
318+
) {
318319
CHECK_GE(args.Length(), 1);
319320
CHECK(args[0]->IsString());
320321

@@ -331,41 +332,32 @@ void BindingData::GetNearestParentPackageJSON(
331332
path_value_str.push_back(kPathSeparator);
332333
}
333334

334-
auto package_json =
335-
TraverseParent(realm, std::filesystem::path(path_value_str));
335+
args.GetReturnValue().Set(path_value_str);
336+
}
337+
338+
void BindingData::GetNearestParentPackageJSON(
339+
const v8::FunctionCallbackInfo<v8::Value>& args
340+
) {
341+
auto path = FindNearestParentPackageJSON(args);
342+
343+
auto package_json = TraverseParent(realm, std::filesystem::path(path_value_str));
336344

337345
if (package_json != nullptr) {
338346
args.GetReturnValue().Set(package_json->Serialize(realm));
339347
}
340348
}
341349

342350
void BindingData::GetNearestParentPackageJSONType(
343-
const FunctionCallbackInfo<Value>& args) {
344-
CHECK_GE(args.Length(), 1);
345-
CHECK(args[0]->IsString());
346-
347-
Realm* realm = Realm::GetCurrent(args);
348-
BufferValue path_value(realm->isolate(), args[0]);
349-
// Check if the path has a trailing slash. If so, add it after
350-
// ToNamespacedPath() as it will be deleted by ToNamespacedPath()
351-
bool slashCheck = path_value.ToStringView().ends_with(kPathSeparator);
352-
353-
ToNamespacedPath(realm->env(), &path_value);
354-
355-
std::string path_value_str = path_value.ToString();
356-
if (slashCheck) {
357-
path_value_str.push_back(kPathSeparator);
358-
}
359-
360-
auto package_json =
361-
TraverseParent(realm, std::filesystem::path(path_value_str));
351+
const FunctionCallbackInfo<Value>& args
352+
) {
353+
auto package_json = GetNearestParentPackageJSON(args);
362354

363355
if (package_json == nullptr) {
364356
return;
365357
}
366358

367-
Local<Value> value =
368-
ToV8Value(realm->context(), package_json->type).ToLocalChecked();
359+
Local<Value> value = ToV8Value(realm->context(), package_json->type).ToLocalChecked();
360+
369361
args.GetReturnValue().Set(value);
370362
}
371363

@@ -497,6 +489,7 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
497489
SetMethod(isolate, target, "getPackageScopeConfig", GetPackageScopeConfig);
498490
SetMethod(isolate, target, "enableCompileCache", EnableCompileCache);
499491
SetMethod(isolate, target, "getCompileCacheDir", GetCompileCacheDir);
492+
SetMethod(isolate, target, "findNearestPackageJSON", FindNearestParentPackageJSON);
500493
SetMethod(isolate, target, "flushCompileCache", FlushCompileCache);
501494
}
502495

typings/internalBinding/modules.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ export type PackageConfig = {
88
exports?: string | string[] | Record<string, unknown>
99
imports?: string | string[] | Record<string, unknown>
1010
}
11+
export type FullPackageConfig = PackageConfig & {
12+
[key: string]: unknown,
13+
}
1114
export type SerializedPackageConfig = [
1215
PackageConfig['name'],
1316
PackageConfig['main'],
@@ -23,4 +26,5 @@ export interface ModulesBinding {
2326
getNearestParentPackageJSONType(path: string): PackageConfig['type']
2427
getPackageScopeConfig(path: string): SerializedPackageConfig | undefined
2528
getPackageJSONScripts(): string | undefined
29+
findNearestPackageJSON(origin: URL['pathname']): URL['pathname'] | undefined
2630
}

0 commit comments

Comments
 (0)