• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const {
4  ObjectDefineProperty,
5  SafeMap,
6} = primordials;
7const {
8  ERR_MANIFEST_DEPENDENCY_MISSING,
9  ERR_UNKNOWN_BUILTIN_MODULE
10} = require('internal/errors').codes;
11const { NativeModule } = require('internal/bootstrap/loaders');
12
13const { validateString } = require('internal/validators');
14const path = require('path');
15const { pathToFileURL, fileURLToPath } = require('internal/url');
16const { URL } = require('url');
17
18let debug = require('internal/util/debuglog').debuglog('module', (fn) => {
19  debug = fn;
20});
21
22function loadNativeModule(filename, request) {
23  const mod = NativeModule.map.get(filename);
24  if (mod) {
25    debug('load native module %s', request);
26    mod.compileForPublicLoader();
27    return mod;
28  }
29}
30
31// Invoke with makeRequireFunction(module) where |module| is the Module object
32// to use as the context for the require() function.
33// Use redirects to set up a mapping from a policy and restrict dependencies
34const urlToFileCache = new SafeMap();
35function makeRequireFunction(mod, redirects) {
36  const Module = mod.constructor;
37
38  let require;
39  if (redirects) {
40    const { resolve, reaction } = redirects;
41    const id = mod.filename || mod.id;
42    require = function require(path) {
43      let missing = true;
44      const destination = resolve(path);
45      if (destination === true) {
46        missing = false;
47      } else if (destination) {
48        const href = destination.href;
49        if (destination.protocol === 'node:') {
50          const specifier = destination.pathname;
51          const mod = loadNativeModule(specifier, href);
52          if (mod && mod.canBeRequiredByUsers) {
53            return mod.exports;
54          }
55          throw new ERR_UNKNOWN_BUILTIN_MODULE(specifier);
56        } else if (destination.protocol === 'file:') {
57          let filepath;
58          if (urlToFileCache.has(href)) {
59            filepath = urlToFileCache.get(href);
60          } else {
61            filepath = fileURLToPath(destination);
62            urlToFileCache.set(href, filepath);
63          }
64          return mod.require(filepath);
65        }
66      }
67      if (missing) {
68        reaction(new ERR_MANIFEST_DEPENDENCY_MISSING(id, path));
69      }
70      return mod.require(path);
71    };
72  } else {
73    require = function require(path) {
74      return mod.require(path);
75    };
76  }
77
78  function resolve(request, options) {
79    validateString(request, 'request');
80    return Module._resolveFilename(request, mod, false, options);
81  }
82
83  require.resolve = resolve;
84
85  function paths(request) {
86    validateString(request, 'request');
87    return Module._resolveLookupPaths(request, mod);
88  }
89
90  resolve.paths = paths;
91
92  require.main = process.mainModule;
93
94  // Enable support to add extra extension types.
95  require.extensions = Module._extensions;
96
97  require.cache = Module._cache;
98
99  return require;
100}
101
102/**
103 * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
104 * because the buffer-to-string conversion in `fs.readFileSync()`
105 * translates it to FEFF, the UTF-16 BOM.
106 */
107function stripBOM(content) {
108  if (content.charCodeAt(0) === 0xFEFF) {
109    content = content.slice(1);
110  }
111  return content;
112}
113
114const builtinLibs = [
115  'assert',
116  'async_hooks',
117  'buffer',
118  'child_process',
119  'cluster',
120  'crypto',
121  'dgram',
122  'dns',
123  'domain',
124  'events',
125  'fs',
126  'http',
127  'http2',
128  'https',
129  'net',
130  'os',
131  'path',
132  'perf_hooks',
133  'punycode',
134  'querystring',
135  'readline',
136  'repl',
137  'stream',
138  'string_decoder',
139  'tls',
140  'trace_events',
141  'tty',
142  'url',
143  'util',
144  'v8',
145  'vm',
146  'worker_threads',
147  'zlib',
148];
149
150if (internalBinding('config').experimentalWasi) {
151  builtinLibs.push('wasi');
152  builtinLibs.sort();
153}
154
155if (typeof internalBinding('inspector').open === 'function') {
156  builtinLibs.push('inspector');
157  builtinLibs.sort();
158}
159
160function addBuiltinLibsToObject(object) {
161  // Make built-in modules available directly (loaded lazily).
162  builtinLibs.forEach((name) => {
163    // Goals of this mechanism are:
164    // - Lazy loading of built-in modules
165    // - Having all built-in modules available as non-enumerable properties
166    // - Allowing the user to re-assign these variables as if there were no
167    //   pre-existing globals with the same name.
168
169    const setReal = (val) => {
170      // Deleting the property before re-assigning it disables the
171      // getter/setter mechanism.
172      delete object[name];
173      object[name] = val;
174    };
175
176    ObjectDefineProperty(object, name, {
177      get: () => {
178        const lib = require(name);
179
180        // Disable the current getter/setter and set up a new
181        // non-enumerable property.
182        delete object[name];
183        ObjectDefineProperty(object, name, {
184          get: () => lib,
185          set: setReal,
186          configurable: true,
187          enumerable: false
188        });
189
190        return lib;
191      },
192      set: setReal,
193      configurable: true,
194      enumerable: false
195    });
196  });
197}
198
199function normalizeReferrerURL(referrer) {
200  if (typeof referrer === 'string' && path.isAbsolute(referrer)) {
201    return pathToFileURL(referrer).href;
202  }
203  return new URL(referrer).href;
204}
205
206module.exports = {
207  addBuiltinLibsToObject,
208  builtinLibs,
209  loadNativeModule,
210  makeRequireFunction,
211  normalizeReferrerURL,
212  stripBOM,
213};
214