Skip to content

Commit 2690c64

Browse files
committed
src: add node_modules.h for module loader
1 parent cd6b86b commit 2690c64

16 files changed

+392
-151
lines changed

lib/internal/modules/package_json_reader.js

Lines changed: 23 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,35 @@
11
'use strict';
22

33
const {
4-
JSONParse,
5-
ObjectPrototypeHasOwnProperty,
6-
SafeMap,
74
StringPrototypeEndsWith,
85
StringPrototypeIndexOf,
96
StringPrototypeLastIndexOf,
107
StringPrototypeSlice,
118
} = primordials;
12-
const {
13-
ERR_INVALID_PACKAGE_CONFIG,
14-
} = require('internal/errors').codes;
15-
const { internalModuleReadJSON } = internalBinding('fs');
9+
const modulesBinding = internalBinding('modules');
1610
const { resolve, sep, toNamespacedPath } = require('path');
1711
const permission = require('internal/process/permission');
18-
const { kEmptyObject, setOwnProperty } = require('internal/util');
19-
20-
const { fileURLToPath, pathToFileURL } = require('internal/url');
12+
const { kEmptyObject } = require('internal/util');
2113

22-
const cache = new SafeMap();
14+
const { pathToFileURL } = require('internal/url');
2315

2416
let manifest;
25-
26-
/**
27-
* @typedef {{
28-
* exists: boolean,
29-
* pjsonPath: string,
30-
* exports?: string | string[] | Record<string, unknown>,
31-
* imports?: string | string[] | Record<string, unknown>,
32-
* name?: string,
33-
* main?: string,
34-
* type: 'commonjs' | 'module' | 'none',
35-
* }} PackageConfig
36-
*/
37-
3817
/**
3918
* @param {string} jsonPath
4019
* @param {{
4120
* base?: string,
4221
* specifier: string,
4322
* isESM: boolean,
4423
* }} options
45-
* @returns {PackageConfig}
24+
* @returns {import('typings/internalBinding/modules').PackageConfig}
4625
*/
4726
function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
48-
if (cache.has(jsonPath)) {
49-
return cache.get(jsonPath);
50-
}
51-
52-
const string = internalModuleReadJSON(
27+
const parsed = modulesBinding.readPackageJSON(
5328
toNamespacedPath(jsonPath),
5429
);
55-
const result = {
56-
__proto__: null,
57-
exists: false,
58-
pjsonPath: jsonPath,
59-
main: undefined,
60-
name: undefined,
61-
type: 'none', // Ignore unknown types for forwards compatibility
62-
exports: undefined,
63-
imports: undefined,
64-
};
65-
66-
if (string !== undefined) {
67-
let parsed;
68-
try {
69-
parsed = JSONParse(string);
70-
} catch (cause) {
71-
const error = new ERR_INVALID_PACKAGE_CONFIG(
72-
jsonPath,
73-
isESM && (base ? `"${specifier}" from ` : '') + fileURLToPath(base || specifier),
74-
cause.message,
75-
);
76-
setOwnProperty(error, 'cause', cause);
77-
throw error;
78-
}
79-
80-
result.exists = true;
8130

82-
// ObjectPrototypeHasOwnProperty is used to avoid prototype pollution.
83-
if (ObjectPrototypeHasOwnProperty(parsed, 'name') && typeof parsed.name === 'string') {
84-
result.name = parsed.name;
85-
}
86-
87-
if (ObjectPrototypeHasOwnProperty(parsed, 'main') && typeof parsed.main === 'string') {
88-
result.main = parsed.main;
89-
}
90-
91-
if (ObjectPrototypeHasOwnProperty(parsed, 'exports')) {
92-
result.exports = parsed.exports;
93-
}
94-
95-
if (ObjectPrototypeHasOwnProperty(parsed, 'imports')) {
96-
result.imports = parsed.imports;
97-
}
98-
99-
// Ignore unknown types for forwards compatibility
100-
if (ObjectPrototypeHasOwnProperty(parsed, 'type') && (parsed.type === 'commonjs' || parsed.type === 'module')) {
101-
result.type = parsed.type;
102-
}
31+
if (parsed !== undefined) {
32+
parsed.pjsonPath = jsonPath;
10333

10434
if (manifest === undefined) {
10535
const { getOptionValue } = require('internal/options');
@@ -108,12 +38,24 @@ function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
10838
null;
10939
}
11040
if (manifest !== null) {
111-
const jsonURL = pathToFileURL(jsonPath);
112-
manifest.assertIntegrity(jsonURL, string);
41+
// TODO(@anonrig): Find a way to assert integrity without returning string.
42+
// const jsonURL = pathToFileURL(jsonPath);
43+
// manifest.assertIntegrity(jsonURL, string);
11344
}
45+
46+
return parsed;
11447
}
115-
cache.set(jsonPath, result);
116-
return result;
48+
49+
return {
50+
__proto__: null,
51+
exists: false,
52+
pjsonPath: jsonPath,
53+
main: undefined,
54+
name: undefined,
55+
type: 'none', // Ignore unknown types for forwards compatibility
56+
exports: undefined,
57+
imports: undefined,
58+
};
11759
}
11860

11961
/**

lib/internal/modules/run_main.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const {
55
} = primordials;
66

77
const { containsModuleSyntax } = internalBinding('contextify');
8+
const { getPackageJSONType } = internalBinding('modules');
89
const { getOptionValue } = require('internal/options');
910
const path = require('path');
1011

@@ -68,10 +69,10 @@ function shouldUseESMLoader(mainPath) {
6869
if (mainPath && StringPrototypeEndsWith(mainPath, '.mjs')) { return true; }
6970
if (!mainPath || StringPrototypeEndsWith(mainPath, '.cjs')) { return false; }
7071

71-
const { readPackageScope } = require('internal/modules/package_json_reader');
72-
const pkg = readPackageScope(mainPath);
73-
// No need to guard `pkg` as it can only be an object or `false`.
74-
switch (pkg.data?.type) {
72+
// TODO(@anonrig): Move resolve functionality to C++.
73+
const type = getPackageJSONType(path.resolve(mainPath, 'package.json'));
74+
75+
switch (type) {
7576
case 'module':
7677
return true;
7778
case 'commonjs':

node.gyp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
'src/node_main_instance.cc',
113113
'src/node_messaging.cc',
114114
'src/node_metadata.cc',
115+
'src/node_modules.cc',
115116
'src/node_options.cc',
116117
'src/node_os.cc',
117118
'src/node_perf.cc',
@@ -234,6 +235,7 @@
234235
'src/node_messaging.h',
235236
'src/node_metadata.h',
236237
'src/node_mutex.h',
238+
'src/node_modules.h',
237239
'src/node_object_wrap.h',
238240
'src/node_options.h',
239241
'src/node_options-inl.h',

src/base_object_types.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ namespace node {
1717
V(blob_binding_data, BlobBindingData) \
1818
V(process_binding_data, process::BindingData) \
1919
V(timers_binding_data, timers::BindingData) \
20-
V(url_binding_data, url::BindingData)
20+
V(url_binding_data, url::BindingData) \
21+
V(modules_binding_data, modules::BindingData)
2122

2223
#define UNSERIALIZABLE_BINDING_TYPES(V) \
2324
V(http2_binding_data, http2::BindingData) \

src/node_binding.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
V(js_stream) \
5050
V(js_udp_wrap) \
5151
V(messaging) \
52+
V(modules) \
5253
V(module_wrap) \
5354
V(mksnapshot) \
5455
V(options) \

src/node_binding.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static_assert(static_cast<int>(NM_F_LINKED) ==
3838
V(encoding_binding) \
3939
V(fs) \
4040
V(mksnapshot) \
41+
V(modules) \
4142
V(timers) \
4243
V(process_methods) \
4344
V(performance) \

src/node_errors.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ void AppendExceptionLine(Environment* env,
7171
V(ERR_INVALID_ARG_TYPE, TypeError) \
7272
V(ERR_INVALID_FILE_URL_HOST, TypeError) \
7373
V(ERR_INVALID_FILE_URL_PATH, TypeError) \
74+
V(ERR_INVALID_PACKAGE_CONFIG, Error) \
7475
V(ERR_INVALID_OBJECT_DEFINE_PROPERTY, TypeError) \
7576
V(ERR_INVALID_MODULE, Error) \
7677
V(ERR_INVALID_STATE, Error) \

src/node_external_reference.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class ExternalReferenceRegistry {
100100
V(messaging) \
101101
V(mksnapshot) \
102102
V(module_wrap) \
103+
V(modules) \
103104
V(options) \
104105
V(os) \
105106
V(performance) \

src/node_file.cc

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,68 +1050,6 @@ static void ExistsSync(const FunctionCallbackInfo<Value>& args) {
10501050
args.GetReturnValue().Set(err == 0);
10511051
}
10521052

1053-
// Used to speed up module loading. Returns an array [string, boolean]
1054-
static void InternalModuleReadJSON(const FunctionCallbackInfo<Value>& args) {
1055-
Environment* env = Environment::GetCurrent(args);
1056-
Isolate* isolate = env->isolate();
1057-
uv_loop_t* loop = env->event_loop();
1058-
1059-
CHECK(args[0]->IsString());
1060-
node::Utf8Value path(isolate, args[0]);
1061-
THROW_IF_INSUFFICIENT_PERMISSIONS(
1062-
env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
1063-
1064-
if (strlen(*path) != path.length()) {
1065-
return; // Contains a nul byte.
1066-
}
1067-
uv_fs_t open_req;
1068-
const int fd = uv_fs_open(loop, &open_req, *path, O_RDONLY, 0, nullptr);
1069-
uv_fs_req_cleanup(&open_req);
1070-
1071-
if (fd < 0) {
1072-
return;
1073-
}
1074-
1075-
auto defer_close = OnScopeLeave([fd, loop]() {
1076-
uv_fs_t close_req;
1077-
CHECK_EQ(0, uv_fs_close(loop, &close_req, fd, nullptr));
1078-
uv_fs_req_cleanup(&close_req);
1079-
});
1080-
1081-
const size_t kBlockSize = 32 << 10;
1082-
std::vector<char> chars;
1083-
int64_t offset = 0;
1084-
ssize_t numchars;
1085-
do {
1086-
const size_t start = chars.size();
1087-
chars.resize(start + kBlockSize);
1088-
1089-
uv_buf_t buf;
1090-
buf.base = &chars[start];
1091-
buf.len = kBlockSize;
1092-
1093-
uv_fs_t read_req;
1094-
numchars = uv_fs_read(loop, &read_req, fd, &buf, 1, offset, nullptr);
1095-
uv_fs_req_cleanup(&read_req);
1096-
1097-
if (numchars < 0) {
1098-
return;
1099-
}
1100-
offset += numchars;
1101-
} while (static_cast<size_t>(numchars) == kBlockSize);
1102-
1103-
size_t start = 0;
1104-
if (offset >= 3 && 0 == memcmp(chars.data(), "\xEF\xBB\xBF", 3)) {
1105-
start = 3; // Skip UTF-8 BOM.
1106-
}
1107-
const size_t size = offset - start;
1108-
1109-
args.GetReturnValue().Set(
1110-
String::NewFromUtf8(
1111-
isolate, &chars[start], v8::NewStringType::kNormal, size)
1112-
.ToLocalChecked());
1113-
}
1114-
11151053
// Used to speed up module loading. Returns 0 if the path refers to
11161054
// a file, 1 when it's a directory or < 0 on error (usually -ENOENT.)
11171055
// The speedup comes from not creating thousands of Stat and Error objects.
@@ -3255,7 +3193,6 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
32553193
SetMethod(isolate, target, "rmdir", RMDir);
32563194
SetMethod(isolate, target, "mkdir", MKDir);
32573195
SetMethod(isolate, target, "readdir", ReadDir);
3258-
SetMethod(isolate, target, "internalModuleReadJSON", InternalModuleReadJSON);
32593196
SetMethod(isolate, target, "internalModuleStat", InternalModuleStat);
32603197
SetMethod(isolate, target, "stat", Stat);
32613198
SetMethod(isolate, target, "lstat", LStat);
@@ -3375,7 +3312,6 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
33753312
registry->Register(RMDir);
33763313
registry->Register(MKDir);
33773314
registry->Register(ReadDir);
3378-
registry->Register(InternalModuleReadJSON);
33793315
registry->Register(InternalModuleStat);
33803316
registry->Register(Stat);
33813317
registry->Register(LStat);

0 commit comments

Comments
 (0)