@@ -34,13 +34,15 @@ const { emitWarningSync } = require('internal/process/warning');
3434const lazyTmpdir = getLazy ( ( ) => require ( 'os' ) . tmpdir ( ) ) ;
3535const { join } = path ;
3636
37+ const internalFsBinding = internalBinding ( 'fs' ) ;
3738const { canParse : URLCanParse } = internalBinding ( 'url' ) ;
39+ const modulesBinding = internalBinding ( 'modules' ) ;
3840const {
3941 enableCompileCache : _enableCompileCache ,
4042 getCompileCacheDir : _getCompileCacheDir ,
4143 compileCacheStatus : _compileCacheStatus ,
4244 flushCompileCache,
43- } = internalBinding ( 'modules' ) ;
45+ } = modulesBinding ;
4446
4547const lazyCJSLoader = getLazy ( ( ) => require ( 'internal/modules/cjs/loader' ) ) ;
4648let debug = require ( 'internal/util/debuglog' ) . debuglog ( 'module' , ( fn ) => {
@@ -56,17 +58,167 @@ let debug = require('internal/util/debuglog').debuglog('module', (fn) => {
5658 * @type {Map<string, string> }
5759 */
5860const realpathCache = new SafeMap ( ) ;
61+ // Toggleable loader fs overrides for VFS support.
62+ // When null, the fast path (no VFS) is taken with zero overhead.
63+ let _loaderStat = null ;
64+ let _loaderReadFile = null ;
65+ let _loaderRealpath = null ;
66+ let _loaderLegacyMainResolve = null ;
67+ let _loaderGetFormatOfExtensionlessFile = null ;
68+
69+ /**
70+ * Set override functions for the module loader's fs operations.
71+ * @param {{ stat?: Function, readFile?: Function, realpath?: Function,
72+ * legacyMainResolve?: Function, getFormatOfExtensionlessFile?: Function }} overrides
73+ */
74+ function setLoaderFsOverrides ( { stat, readFile, realpath, legacyMainResolve, getFormatOfExtensionlessFile } ) {
75+ _loaderStat = stat ;
76+ _loaderReadFile = readFile ;
77+ _loaderRealpath = realpath ;
78+ _loaderLegacyMainResolve = legacyMainResolve ;
79+ _loaderGetFormatOfExtensionlessFile = getFormatOfExtensionlessFile ;
80+ }
81+
82+ /**
83+ * Wrapper for internalModuleStat that supports VFS toggle.
84+ * @param {string } filename Absolute path to stat
85+ * @returns {number }
86+ */
87+ function loaderStat ( filename ) {
88+ if ( _loaderStat !== null ) { return _loaderStat ( filename ) ; }
89+ return internalFsBinding . internalModuleStat ( filename ) ;
90+ }
91+
92+ /**
93+ * Wrapper for fs.readFileSync that supports VFS toggle.
94+ * @param {string|URL } filename Path to read
95+ * @param {string|object } options Read options
96+ * @returns {string|Buffer }
97+ */
98+ function loaderReadFile ( filename , options ) {
99+ if ( _loaderReadFile !== null ) {
100+ const result = _loaderReadFile ( filename , options ) ;
101+ if ( result !== undefined ) { return result ; }
102+ }
103+ return fs . readFileSync ( filename , options ) ;
104+ }
105+
59106/**
60107 * Resolves the path of a given `require` specifier, following symlinks.
61108 * @param {string } requestPath The `require` specifier
62109 * @returns {string }
63110 */
64111function toRealPath ( requestPath ) {
112+ if ( _loaderRealpath !== null ) {
113+ const result = _loaderRealpath ( requestPath ) ;
114+ if ( result !== undefined ) { return result ; }
115+ }
65116 return fs . realpathSync ( requestPath , {
66117 [ internalFS . realpathCacheKey ] : realpathCache ,
67118 } ) ;
68119}
69120
121+ /**
122+ * Wrapper for internalBinding('fs').legacyMainResolve that supports VFS toggle.
123+ * @param {string } pkgPath The package directory path
124+ * @param {string } main The package main field
125+ * @param {string } base The base URL string
126+ * @returns {number }
127+ */
128+ function loaderLegacyMainResolve ( pkgPath , main , base ) {
129+ if ( _loaderLegacyMainResolve !== null ) {
130+ const result = _loaderLegacyMainResolve ( pkgPath , main , base ) ;
131+ if ( result !== undefined ) { return result ; }
132+ }
133+ return internalFsBinding . legacyMainResolve ( pkgPath , main , base ) ;
134+ }
135+
136+ /**
137+ * Wrapper for internalBinding('fs').getFormatOfExtensionlessFile that supports VFS toggle.
138+ * @param {string } path The file path
139+ * @returns {number }
140+ */
141+ function loaderGetFormatOfExtensionlessFile ( path ) {
142+ if ( _loaderGetFormatOfExtensionlessFile !== null ) {
143+ const result = _loaderGetFormatOfExtensionlessFile ( path ) ;
144+ if ( result !== undefined ) { return result ; }
145+ }
146+ return internalFsBinding . getFormatOfExtensionlessFile ( path ) ;
147+ }
148+
149+ // Toggleable overrides for package.json C++ methods (VFS support).
150+ let _loaderReadPackageJSON = null ;
151+ let _loaderGetNearestParentPackageJSON = null ;
152+ let _loaderGetPackageScopeConfig = null ;
153+ let _loaderGetPackageType = null ;
154+
155+ /**
156+ * Set override functions for the module loader's package.json operations.
157+ * @param {{
158+ * readPackageJSON?: Function,
159+ * getNearestParentPackageJSON?: Function,
160+ * getPackageScopeConfig?: Function,
161+ * getPackageType?: Function,
162+ * }} overrides
163+ */
164+ function setLoaderPackageOverrides ( overrides ) {
165+ _loaderReadPackageJSON = overrides . readPackageJSON ;
166+ _loaderGetNearestParentPackageJSON = overrides . getNearestParentPackageJSON ;
167+ _loaderGetPackageScopeConfig = overrides . getPackageScopeConfig ;
168+ _loaderGetPackageType = overrides . getPackageType ;
169+ }
170+
171+ /**
172+ * Wrapper for modulesBinding.readPackageJSON that supports VFS toggle.
173+ * @param {string } jsonPath
174+ * @param {boolean } isESM
175+ * @param {string } base
176+ * @param {string } specifier
177+ * @returns {object|undefined }
178+ */
179+ function loaderReadPackageJSON ( jsonPath , isESM , base , specifier ) {
180+ if ( _loaderReadPackageJSON !== null ) {
181+ return _loaderReadPackageJSON ( jsonPath , isESM , base , specifier ) ;
182+ }
183+ return modulesBinding . readPackageJSON ( jsonPath , isESM , base , specifier ) ;
184+ }
185+
186+ /**
187+ * Wrapper for modulesBinding.getNearestParentPackageJSON that supports VFS toggle.
188+ * @param {string } checkPath
189+ * @returns {object|undefined }
190+ */
191+ function loaderGetNearestParentPackageJSON ( checkPath ) {
192+ if ( _loaderGetNearestParentPackageJSON !== null ) {
193+ return _loaderGetNearestParentPackageJSON ( checkPath ) ;
194+ }
195+ return modulesBinding . getNearestParentPackageJSON ( checkPath ) ;
196+ }
197+
198+ /**
199+ * Wrapper for modulesBinding.getPackageScopeConfig that supports VFS toggle.
200+ * @param {string } resolved
201+ * @returns {object|string }
202+ */
203+ function loaderGetPackageScopeConfig ( resolved ) {
204+ if ( _loaderGetPackageScopeConfig !== null ) {
205+ return _loaderGetPackageScopeConfig ( resolved ) ;
206+ }
207+ return modulesBinding . getPackageScopeConfig ( resolved ) ;
208+ }
209+
210+ /**
211+ * Wrapper for modulesBinding.getPackageType that supports VFS toggle.
212+ * @param {string } url
213+ * @returns {string|undefined }
214+ */
215+ function loaderGetPackageType ( url ) {
216+ if ( _loaderGetPackageType !== null ) {
217+ return _loaderGetPackageType ( url ) ;
218+ }
219+ return modulesBinding . getPackageType ( url ) ;
220+ }
221+
70222/** @type {Set<string> } */
71223let cjsConditions ;
72224/** @type {string[] } */
@@ -524,10 +676,20 @@ module.exports = {
524676 getCjsConditionsArray,
525677 getCompileCacheDir,
526678 initializeCjsConditions,
679+ loaderGetFormatOfExtensionlessFile,
680+ loaderGetNearestParentPackageJSON,
681+ loaderGetPackageScopeConfig,
682+ loaderGetPackageType,
683+ loaderLegacyMainResolve,
684+ loaderReadFile,
685+ loaderReadPackageJSON,
686+ loaderStat,
527687 loadBuiltinModuleForEmbedder,
528688 loadBuiltinModule,
529689 makeRequireFunction,
530690 normalizeReferrerURL,
691+ setLoaderFsOverrides,
692+ setLoaderPackageOverrides,
531693 stringify,
532694 stripBOM,
533695 toRealPath,
0 commit comments