Skip to content

Commit 03a0242

Browse files
committed
vfs: replace monkeypatching with self-contained module.registerHooks
Replace 8 monkeypatched internal functions with self-contained resolve and load hooks using module.registerHooks(). The resolve hook now handles bare specifiers (node_modules walking + package.json exports resolution), relative paths, absolute paths, and file: URLs entirely within VFS. The load hook uses a local format map, eliminating the problematic esm/formats lazy dependency. Remove ~140 lines of toggle infrastructure from helpers.js and package_json_reader.js, reverting them to direct implementations. Revert esm/resolve.js to use internalBinding('fs') directly.
1 parent e3c2ffb commit 03a0242

File tree

6 files changed

+437
-453
lines changed

6 files changed

+437
-453
lines changed

lib/internal/modules/esm/resolve.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ const {
2323
} = primordials;
2424
const assert = require('internal/assert');
2525
const { BuiltinModule } = require('internal/bootstrap/realm');
26-
const { toRealPath, internalModuleStat } = require('internal/modules/helpers');
26+
const { toRealPath } = require('internal/modules/helpers');
27+
const internalFsBinding = internalBinding('fs');
2728
const { getOptionValue } = require('internal/options');
2829
// Do not eagerly grab .manifest, it may be in TDZ
2930
const { sep, posix: { relative: relativePosixPath }, resolve } = require('path');
@@ -239,7 +240,7 @@ function finalizeResolution(resolved, base, preserveSymlinks) {
239240
throw err;
240241
}
241242

242-
const stats = internalModuleStat(
243+
const stats = internalFsBinding.internalModuleStat(
243244
StringPrototypeEndsWith(path, '/') ? StringPrototypeSlice(path, -1) : path,
244245
);
245246

lib/internal/modules/helpers.js

Lines changed: 4 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -56,109 +56,25 @@ let debug = require('internal/util/debuglog').debuglog('module', (fn) => {
5656
*/
5757
const realpathCache = new SafeMap();
5858

59-
let customToRealPath = null;
60-
6159
/**
62-
* Default implementation: resolves the path following symlinks.
60+
* Resolves the path of a given `require` specifier, following symlinks.
6361
* @param {string} requestPath The `require` specifier
6462
* @returns {string}
6563
*/
66-
function defaultToRealPath(requestPath) {
64+
function toRealPath(requestPath) {
6765
return fs.realpathSync(requestPath, {
6866
[internalFS.realpathCacheKey]: realpathCache,
6967
});
7068
}
7169

7270
/**
73-
* Resolves the path of a given `require` specifier, following symlinks.
74-
* When a custom override is set (e.g. for VFS), it is called first.
75-
* @param {string} requestPath The `require` specifier
76-
* @returns {string}
77-
*/
78-
function toRealPath(requestPath) {
79-
if (customToRealPath !== null) {
80-
return customToRealPath(requestPath, defaultToRealPath);
81-
}
82-
return defaultToRealPath(requestPath);
83-
}
84-
85-
/**
86-
* Set a custom toRealPath override (e.g. for VFS-aware resolution).
87-
* The function receives (requestPath, defaultToRealPath) and should
88-
* return the resolved real path.
89-
* @param {Function|null} fn The custom function, or null to reset
90-
*/
91-
function setCustomToRealPath(fn) {
92-
customToRealPath = fn;
93-
}
94-
95-
let customReadFileSync = null;
96-
97-
/**
98-
* Default implementation: reads a file from disk.
99-
* @param {string} path The file path
100-
* @param {string|object} options Read options
101-
* @returns {string|Buffer}
102-
*/
103-
function defaultReadFileSync(path, options) {
104-
return fs.readFileSync(path, options);
105-
}
106-
107-
/**
108-
* Reads a file, delegating to a custom override when set (e.g. for VFS).
71+
* Reads a file from disk.
10972
* @param {string} path The file path
11073
* @param {string|object} options Read options
11174
* @returns {string|Buffer}
11275
*/
11376
function readFileSync(path, options) {
114-
if (customReadFileSync !== null) {
115-
return customReadFileSync(path, options, defaultReadFileSync);
116-
}
117-
return defaultReadFileSync(path, options);
118-
}
119-
120-
/**
121-
* Set a custom readFileSync override (e.g. for VFS-aware reading).
122-
* The function receives (path, options, defaultReadFileSync) and should
123-
* return the file content.
124-
* @param {Function|null} fn The custom function, or null to reset
125-
*/
126-
function setCustomReadFileSync(fn) {
127-
customReadFileSync = fn;
128-
}
129-
130-
const internalFsBinding = internalBinding('fs');
131-
let customInternalModuleStat = null;
132-
133-
/**
134-
* Default implementation: calls the C++ internalModuleStat binding.
135-
* @param {string} path The file path
136-
* @returns {number} 0 for file, 1 for directory, negative for not found
137-
*/
138-
function defaultInternalModuleStat(path) {
139-
return internalFsBinding.internalModuleStat(path);
140-
}
141-
142-
/**
143-
* Checks the stat of a module path, delegating to a custom override when set.
144-
* @param {string} path The file path
145-
* @returns {number} 0 for file, 1 for directory, negative for not found
146-
*/
147-
function internalModuleStat(path) {
148-
if (customInternalModuleStat !== null) {
149-
return customInternalModuleStat(path, defaultInternalModuleStat);
150-
}
151-
return defaultInternalModuleStat(path);
152-
}
153-
154-
/**
155-
* Set a custom internalModuleStat override (e.g. for VFS-aware stat).
156-
* The function receives (path, defaultInternalModuleStat) and should
157-
* return the stat result.
158-
* @param {Function|null} fn The custom function, or null to reset
159-
*/
160-
function setCustomInternalModuleStat(fn) {
161-
customInternalModuleStat = fn;
77+
return fs.readFileSync(path, options);
16278
}
16379

16480
/** @type {Set<string>} */
@@ -602,15 +518,11 @@ module.exports = {
602518
getCjsConditionsArray,
603519
getCompileCacheDir,
604520
initializeCjsConditions,
605-
internalModuleStat,
606521
loadBuiltinModuleForEmbedder,
607522
loadBuiltinModule,
608523
makeRequireFunction,
609524
normalizeReferrerURL,
610525
readFileSync,
611-
setCustomInternalModuleStat,
612-
setCustomReadFileSync,
613-
setCustomToRealPath,
614526
stringify,
615527
stripBOM,
616528
toRealPath,

lib/internal/modules/package_json_reader.js

Lines changed: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,6 @@ const { validateString } = require('internal/validators');
3535
* @typedef {import('typings/internalBinding/modules').SerializedPackageConfig} SerializedPackageConfig
3636
*/
3737

38-
let customRead = null;
39-
let customGetPackageScopeConfig = null;
40-
let customGetPackageType = null;
41-
let customGetNearestParentPackageJSON = null;
42-
43-
function setCustomRead(fn) {
44-
customRead = fn;
45-
}
46-
47-
function setCustomGetPackageScopeConfig(fn) {
48-
customGetPackageScopeConfig = fn;
49-
}
50-
51-
function setCustomGetPackageType(fn) {
52-
customGetPackageType = fn;
53-
}
54-
55-
function setCustomGetNearestParentPackageJSON(fn) {
56-
customGetNearestParentPackageJSON = fn;
57-
}
58-
5938
/**
6039
* @param {URL['pathname']} path
6140
* @param {SerializedPackageConfig} contents
@@ -139,14 +118,7 @@ const requiresJSONParse = (value) => (value !== undefined && (value[0] === '[' |
139118
* }} opts
140119
* @returns {PackageConfig}
141120
*/
142-
function read(jsonPath, opts) {
143-
if (customRead !== null) {
144-
return customRead(jsonPath, opts, defaultRead);
145-
}
146-
return defaultRead(jsonPath, opts);
147-
}
148-
149-
function defaultRead(jsonPath, { base, specifier, isESM } = kEmptyObject) {
121+
function read(jsonPath, { base, specifier, isESM } = kEmptyObject) {
150122
// This function will be called by both CJS and ESM, so we need to make sure
151123
// non-null attributes are converted to strings.
152124
const parsed = modulesBinding.readPackageJSON(
@@ -192,13 +164,6 @@ const deserializedPackageJSONCache = new SafeMap();
192164
* @returns {undefined | DeserializedPackageConfig}
193165
*/
194166
function getNearestParentPackageJSON(checkPath) {
195-
if (customGetNearestParentPackageJSON !== null) {
196-
return customGetNearestParentPackageJSON(checkPath, defaultGetNearestParentPackageJSON);
197-
}
198-
return defaultGetNearestParentPackageJSON(checkPath);
199-
}
200-
201-
function defaultGetNearestParentPackageJSON(checkPath) {
202167
const parentPackageJSONPath = moduleToParentPackageJSONCache.get(checkPath);
203168
if (parentPackageJSONPath !== undefined) {
204169
return deserializedPackageJSONCache.get(parentPackageJSONPath);
@@ -224,13 +189,6 @@ function defaultGetNearestParentPackageJSON(checkPath) {
224189
* @returns {import('typings/internalBinding/modules').PackageConfig} - The package configuration.
225190
*/
226191
function getPackageScopeConfig(resolved) {
227-
if (customGetPackageScopeConfig !== null) {
228-
return customGetPackageScopeConfig(resolved, defaultGetPackageScopeConfig);
229-
}
230-
return defaultGetPackageScopeConfig(resolved);
231-
}
232-
233-
function defaultGetPackageScopeConfig(resolved) {
234192
const result = modulesBinding.getPackageScopeConfig(`${resolved}`);
235193

236194
if (ArrayIsArray(result)) {
@@ -260,13 +218,6 @@ function defaultGetPackageScopeConfig(resolved) {
260218
* @returns {string}
261219
*/
262220
function getPackageType(url) {
263-
if (customGetPackageType !== null) {
264-
return customGetPackageType(url, defaultGetPackageType);
265-
}
266-
return defaultGetPackageType(url);
267-
}
268-
269-
function defaultGetPackageType(url) {
270221
const type = modulesBinding.getPackageType(`${url}`);
271222
return type ?? 'none';
272223
}
@@ -324,12 +275,12 @@ function getPackageJSONURL(specifier, base) {
324275
}
325276
}
326277

327-
const { internalModuleStat } = require('internal/modules/helpers');
278+
const internalFsBinding = internalBinding('fs');
328279
let packageJSONUrl = new URL(`./node_modules/${packageName}/package.json`, base);
329280
let packageJSONPath = fileURLToPath(packageJSONUrl);
330281
let lastPath;
331282
do {
332-
const stat = internalModuleStat(
283+
const stat = internalFsBinding.internalModuleStat(
333284
StringPrototypeSlice(packageJSONPath, 0, packageJSONPath.length - 13),
334285
);
335286
// Check for !stat.isDirectory()
@@ -409,8 +360,4 @@ module.exports = {
409360
getPackageType,
410361
getPackageJSONURL,
411362
findPackageJSON,
412-
setCustomRead,
413-
setCustomGetPackageScopeConfig,
414-
setCustomGetPackageType,
415-
setCustomGetNearestParentPackageJSON,
416363
};

0 commit comments

Comments
 (0)