1 |
|
2 |
|
3 |
|
4 |
|
5 | 'use strict';
|
6 |
|
7 | const {
|
8 | ArrayIsArray,
|
9 | ArrayPrototypeIncludes,
|
10 | ArrayPrototypeJoin,
|
11 | ArrayPrototypePush,
|
12 | JSONParse,
|
13 | ObjectKeys,
|
14 | RegExpPrototypeTest,
|
15 | SafeMap,
|
16 | SafeWeakMap,
|
17 | StringPrototypeCharCodeAt,
|
18 | StringPrototypeEndsWith,
|
19 | StringPrototypeLastIndexOf,
|
20 | StringPrototypeIndexOf,
|
21 | StringPrototypeMatch,
|
22 | StringPrototypeSlice,
|
23 | StringPrototypeStartsWith,
|
24 | } = require('./node-primordials');
|
25 | const { NativeModule } = require('./node-nativemodule');
|
26 | const { pathToFileURL, fileURLToPath } = require('url');
|
27 | const fs = require('fs');
|
28 | const path = require('path');
|
29 | const { sep } = path;
|
30 | const { internalModuleStat } = require('./node-internalBinding-fs');
|
31 | const packageJsonReader = require('./node-internal-modules-package_json_reader');
|
32 | const {
|
33 | cjsConditions,
|
34 | } = require('./node-internal-modules-cjs-helpers');
|
35 | const { getOptionValue } = require('./node-options');
|
36 | const preserveSymlinks = getOptionValue('--preserve-symlinks');
|
37 | const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
|
38 | const {normalizeSlashes} = require('../dist/util');
|
39 | const {createErrRequireEsm} = require('./node-internal-errors');
|
40 | const {
|
41 | codes: {
|
42 | ERR_INVALID_MODULE_SPECIFIER,
|
43 | },
|
44 | } = require('./node-internal-errors');
|
45 |
|
46 | const {
|
47 | CHAR_FORWARD_SLASH,
|
48 | } = require('./node-internal-constants');
|
49 |
|
50 | const Module = require('module');
|
51 |
|
52 | const isWindows = process.platform === 'win32';
|
53 |
|
54 | let statCache = null;
|
55 |
|
56 | function stat(filename) {
|
57 | filename = path.toNamespacedPath(filename);
|
58 | if (statCache !== null) {
|
59 | const result = statCache.get(filename);
|
60 | if (result !== undefined) return result;
|
61 | }
|
62 | const result = internalModuleStat(filename);
|
63 | if (statCache !== null && result >= 0) {
|
64 |
|
65 | statCache.set(filename, result);
|
66 | }
|
67 | return result;
|
68 | }
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 | const moduleParentCache = new SafeWeakMap();
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 | const packageJsonCache = new SafeMap();
|
89 |
|
90 | function readPackage(requestPath) {
|
91 | const jsonPath = path.resolve(requestPath, 'package.json');
|
92 |
|
93 | const existing = packageJsonCache.get(jsonPath);
|
94 | if (existing !== undefined) return existing;
|
95 |
|
96 | const result = packageJsonReader.read(jsonPath);
|
97 | const json = result.containsKeys === false ? '{}' : result.string;
|
98 | if (json === undefined) {
|
99 | packageJsonCache.set(jsonPath, false);
|
100 | return false;
|
101 | }
|
102 |
|
103 | try {
|
104 | const parsed = JSONParse(json);
|
105 | const filtered = {
|
106 | name: parsed.name,
|
107 | main: parsed.main,
|
108 | exports: parsed.exports,
|
109 | imports: parsed.imports,
|
110 | type: parsed.type
|
111 | };
|
112 | packageJsonCache.set(jsonPath, filtered);
|
113 | return filtered;
|
114 | } catch (e) {
|
115 | e.path = jsonPath;
|
116 | e.message = 'Error parsing ' + jsonPath + ': ' + e.message;
|
117 | throw e;
|
118 | }
|
119 | }
|
120 |
|
121 | function readPackageScope(checkPath) {
|
122 | const rootSeparatorIndex = StringPrototypeIndexOf(checkPath, sep);
|
123 | let separatorIndex;
|
124 | do {
|
125 | separatorIndex = StringPrototypeLastIndexOf(checkPath, sep);
|
126 | checkPath = StringPrototypeSlice(checkPath, 0, separatorIndex);
|
127 | if (StringPrototypeEndsWith(checkPath, sep + 'node_modules'))
|
128 | return false;
|
129 | const pjson = readPackage(checkPath + sep);
|
130 | if (pjson) return {
|
131 | data: pjson,
|
132 | path: checkPath,
|
133 | };
|
134 | } while (separatorIndex > rootSeparatorIndex);
|
135 | return false;
|
136 | }
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 | function createCjsLoader(opts) {
|
146 | const {nodeEsmResolver, preferTsExts} = opts;
|
147 | const {replacementsForCjs, replacementsForJs, replacementsForMjs, replacementsForJsx} = opts.extensions;
|
148 | const {
|
149 | encodedSepRegEx,
|
150 | packageExportsResolve,
|
151 | packageImportsResolve
|
152 | } = nodeEsmResolver;
|
153 |
|
154 | function tryPackage(requestPath, exts, isMain, originalPath) {
|
155 |
|
156 | const tmp = readPackage(requestPath)
|
157 | const pkg = tmp != null ? tmp.main : undefined;
|
158 |
|
159 | if (!pkg) {
|
160 | return tryExtensions(path.resolve(requestPath, 'index'), exts, isMain);
|
161 | }
|
162 |
|
163 | const filename = path.resolve(requestPath, pkg);
|
164 | let actual = tryReplacementExtensions(filename, isMain) ||
|
165 | tryFile(filename, isMain) ||
|
166 | tryExtensions(filename, exts, isMain) ||
|
167 | tryExtensions(path.resolve(filename, 'index'), exts, isMain);
|
168 | if (actual === false) {
|
169 | actual = tryExtensions(path.resolve(requestPath, 'index'), exts, isMain);
|
170 | if (!actual) {
|
171 |
|
172 | const err = new Error(
|
173 | `Cannot find module '${filename}'. ` +
|
174 | 'Please verify that the package.json has a valid "main" entry'
|
175 | );
|
176 | err.code = 'MODULE_NOT_FOUND';
|
177 | err.path = path.resolve(requestPath, 'package.json');
|
178 | err.requestPath = originalPath;
|
179 |
|
180 | throw err;
|
181 | } else {
|
182 | const jsonPath = path.resolve(requestPath, 'package.json');
|
183 | process.emitWarning(
|
184 | `Invalid 'main' field in '${jsonPath}' of '${pkg}'. ` +
|
185 | 'Please either fix that or report it to the module author',
|
186 | 'DeprecationWarning',
|
187 | 'DEP0128'
|
188 | );
|
189 | }
|
190 | }
|
191 | return actual;
|
192 | }
|
193 |
|
194 |
|
195 |
|
196 |
|
197 | const realpathCache = new SafeMap();
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 | function tryFile(requestPath, isMain) {
|
204 | const rc = stat(requestPath);
|
205 | if (rc !== 0) return;
|
206 | if (preserveSymlinks && !isMain) {
|
207 | return path.resolve(requestPath);
|
208 | }
|
209 | return toRealPath(requestPath);
|
210 | }
|
211 |
|
212 | function toRealPath(requestPath) {
|
213 | return fs.realpathSync(requestPath, {
|
214 |
|
215 | });
|
216 | }
|
217 |
|
218 | function statReplacementExtensions(p) {
|
219 | const lastDotIndex = p.lastIndexOf('.');
|
220 | if(lastDotIndex >= 0) {
|
221 | const ext = p.slice(lastDotIndex);
|
222 | if (ext === '.js' || ext === '.jsx' || ext === '.mjs' || ext === '.cjs') {
|
223 | const pathnameWithoutExtension = p.slice(0, lastDotIndex);
|
224 | const replacementExts =
|
225 | ext === '.js' ? replacementsForJs
|
226 | : ext === '.jsx' ? replacementsForJsx
|
227 | : ext === '.mjs' ? replacementsForMjs
|
228 | : replacementsForCjs;
|
229 | for (let i = 0; i < replacementExts.length; i++) {
|
230 | const filename = pathnameWithoutExtension + replacementExts[i];
|
231 | const rc = stat(filename);
|
232 | if (rc === 0) {
|
233 | return [rc, filename];
|
234 | }
|
235 | }
|
236 | }
|
237 | }
|
238 | return [stat(p), p];
|
239 | }
|
240 | function tryReplacementExtensions(p, isMain) {
|
241 | const lastDotIndex = p.lastIndexOf('.');
|
242 | if(lastDotIndex >= 0) {
|
243 | const ext = p.slice(lastDotIndex);
|
244 | if (ext === '.js' || ext === '.jsx' || ext === '.mjs' || ext === '.cjs') {
|
245 | const pathnameWithoutExtension = p.slice(0, lastDotIndex);
|
246 | const replacementExts =
|
247 | ext === '.js' ? replacementsForJs
|
248 | : ext === '.jsx' ? replacementsForJsx
|
249 | : ext === '.mjs' ? replacementsForMjs
|
250 | : replacementsForCjs;
|
251 | for (let i = 0; i < replacementExts.length; i++) {
|
252 | const filename = tryFile(pathnameWithoutExtension + replacementExts[i], isMain);
|
253 | if (filename) {
|
254 | return filename;
|
255 | }
|
256 | }
|
257 | }
|
258 | }
|
259 | return false;
|
260 | }
|
261 |
|
262 |
|
263 | function tryExtensions(p, exts, isMain) {
|
264 | for (let i = 0; i < exts.length; i++) {
|
265 | const filename = tryFile(p + exts[i], isMain);
|
266 |
|
267 | if (filename) {
|
268 | return filename;
|
269 | }
|
270 | }
|
271 | return false;
|
272 | }
|
273 |
|
274 | function trySelfParentPath(parent) {
|
275 | if (!parent) return false;
|
276 |
|
277 | if (parent.filename) {
|
278 | return parent.filename;
|
279 | } else if (parent.id === '<repl>' || parent.id === 'internal/preload') {
|
280 | try {
|
281 | return process.cwd() + path.sep;
|
282 | } catch {
|
283 | return false;
|
284 | }
|
285 | }
|
286 | }
|
287 |
|
288 | function trySelf(parentPath, request) {
|
289 | if (!parentPath) return false;
|
290 |
|
291 | const { data: pkg, path: pkgPath } = readPackageScope(parentPath) || {};
|
292 | if (!pkg || pkg.exports === undefined) return false;
|
293 | if (typeof pkg.name !== 'string') return false;
|
294 |
|
295 | let expansion;
|
296 | if (request === pkg.name) {
|
297 | expansion = '.';
|
298 | } else if (StringPrototypeStartsWith(request, `${pkg.name}/`)) {
|
299 | expansion = '.' + StringPrototypeSlice(request, pkg.name.length);
|
300 | } else {
|
301 | return false;
|
302 | }
|
303 |
|
304 | try {
|
305 | return finalizeEsmResolution(packageExportsResolve(
|
306 | pathToFileURL(pkgPath + '/package.json'), expansion, pkg,
|
307 | pathToFileURL(parentPath), cjsConditions).resolved, parentPath, pkgPath);
|
308 | } catch (e) {
|
309 | if (e.code === 'ERR_MODULE_NOT_FOUND')
|
310 | throw createEsmNotFoundErr(request, pkgPath + '/package.json');
|
311 | throw e;
|
312 | }
|
313 | }
|
314 |
|
315 |
|
316 |
|
317 |
|
318 | const EXPORTS_PATTERN = /^((?:@[^/\\%]+\/)?[^./\\%][^/\\%]*)(\/.*)?$/;
|
319 | function resolveExports(nmPath, request) {
|
320 |
|
321 | const { 1: name, 2: expansion = '' } =
|
322 | StringPrototypeMatch(request, EXPORTS_PATTERN) || [];
|
323 | if (!name)
|
324 | return;
|
325 | const pkgPath = path.resolve(nmPath, name);
|
326 | const pkg = readPackage(pkgPath);
|
327 |
|
328 | if (pkg != null && pkg.exports != null) {
|
329 | try {
|
330 | return finalizeEsmResolution(packageExportsResolve(
|
331 | pathToFileURL(pkgPath + '/package.json'), '.' + expansion, pkg, null,
|
332 | cjsConditions).resolved, null, pkgPath);
|
333 | } catch (e) {
|
334 | if (e.code === 'ERR_MODULE_NOT_FOUND')
|
335 | throw createEsmNotFoundErr(request, pkgPath + '/package.json');
|
336 | throw e;
|
337 | }
|
338 | }
|
339 | }
|
340 |
|
341 |
|
342 | const hasModulePathCache = !!require('module')._pathCache;
|
343 | const Module_pathCache = Object.create(null);
|
344 | const Module_pathCache_get = hasModulePathCache ? (cacheKey) => Module._pathCache[cacheKey] : (cacheKey) => Module_pathCache[cacheKey];
|
345 | const Module_pathCache_set = hasModulePathCache ? (cacheKey, value) => (Module._pathCache[cacheKey] = value) : (cacheKey) => (Module_pathCache[cacheKey] = value);
|
346 |
|
347 | const trailingSlashRegex = /(?:^|\/)\.?\.$/;
|
348 | const Module_findPath = function _findPath(request, paths, isMain) {
|
349 | const absoluteRequest = path.isAbsolute(request);
|
350 | if (absoluteRequest) {
|
351 | paths = [''];
|
352 | } else if (!paths || paths.length === 0) {
|
353 | return false;
|
354 | }
|
355 |
|
356 | const cacheKey = request + '\x00' + ArrayPrototypeJoin(paths, '\x00');
|
357 | const entry = Module_pathCache_get(cacheKey);
|
358 | if (entry)
|
359 | return entry;
|
360 |
|
361 | let exts;
|
362 | let trailingSlash = request.length > 0 &&
|
363 | StringPrototypeCharCodeAt(request, request.length - 1) ===
|
364 | CHAR_FORWARD_SLASH;
|
365 | if (!trailingSlash) {
|
366 | trailingSlash = RegExpPrototypeTest(trailingSlashRegex, request);
|
367 | }
|
368 |
|
369 |
|
370 | for (let i = 0; i < paths.length; i++) {
|
371 |
|
372 | const curPath = paths[i];
|
373 | if (curPath && stat(curPath) < 1) continue;
|
374 |
|
375 | if (!absoluteRequest) {
|
376 | const exportsResolved = resolveExports(curPath, request);
|
377 | if (exportsResolved)
|
378 | return exportsResolved;
|
379 | }
|
380 |
|
381 | const _basePath = path.resolve(curPath, request);
|
382 | let filename;
|
383 |
|
384 | const [rc, basePath] = statReplacementExtensions(_basePath);
|
385 | if (!trailingSlash) {
|
386 | if (rc === 0) {
|
387 | if (!isMain) {
|
388 | if (preserveSymlinks) {
|
389 | filename = path.resolve(basePath);
|
390 | } else {
|
391 | filename = toRealPath(basePath);
|
392 | }
|
393 | } else if (preserveSymlinksMain) {
|
394 |
|
395 |
|
396 |
|
397 |
|
398 |
|
399 |
|
400 |
|
401 |
|
402 | filename = path.resolve(basePath);
|
403 | } else {
|
404 | filename = toRealPath(basePath);
|
405 | }
|
406 | }
|
407 |
|
408 | if (!filename) {
|
409 |
|
410 | if (exts === undefined)
|
411 | exts = ObjectKeys(Module._extensions);
|
412 | filename = tryExtensions(basePath, exts, isMain);
|
413 | }
|
414 | }
|
415 |
|
416 | if (!filename && rc === 1) {
|
417 |
|
418 | if (exts === undefined)
|
419 | exts = ObjectKeys(Module._extensions);
|
420 | filename = tryPackage(basePath, exts, isMain, request);
|
421 | }
|
422 |
|
423 | if (filename) {
|
424 | Module_pathCache_set(cacheKey, filename);
|
425 | return filename;
|
426 | }
|
427 | }
|
428 |
|
429 | return false;
|
430 | };
|
431 |
|
432 | const Module_resolveFilename = function _resolveFilename(request, parent, isMain, options) {
|
433 | if (StringPrototypeStartsWith(request, 'node:') ||
|
434 | NativeModule.canBeRequiredByUsers(request)) {
|
435 | return request;
|
436 | }
|
437 |
|
438 | let paths;
|
439 |
|
440 | if (typeof options === 'object' && options !== null) {
|
441 | if (ArrayIsArray(options.paths)) {
|
442 | const isRelative = StringPrototypeStartsWith(request, './') ||
|
443 | StringPrototypeStartsWith(request, '../') ||
|
444 | ((isWindows && StringPrototypeStartsWith(request, '.\\')) ||
|
445 | StringPrototypeStartsWith(request, '..\\'));
|
446 |
|
447 | if (isRelative) {
|
448 | paths = options.paths;
|
449 | } else {
|
450 | const fakeParent = new Module('', null);
|
451 |
|
452 | paths = [];
|
453 |
|
454 | for (let i = 0; i < options.paths.length; i++) {
|
455 | const path = options.paths[i];
|
456 | fakeParent.paths = Module._nodeModulePaths(path);
|
457 | const lookupPaths = Module._resolveLookupPaths(request, fakeParent);
|
458 |
|
459 | for (let j = 0; j < lookupPaths.length; j++) {
|
460 | if (!ArrayPrototypeIncludes(paths, lookupPaths[j]))
|
461 | ArrayPrototypePush(paths, lookupPaths[j]);
|
462 | }
|
463 | }
|
464 | }
|
465 | } else if (options.paths === undefined) {
|
466 | paths = Module._resolveLookupPaths(request, parent);
|
467 | } else {
|
468 | throw new ERR_INVALID_ARG_VALUE('options.paths', options.paths);
|
469 | }
|
470 | } else {
|
471 | paths = Module._resolveLookupPaths(request, parent);
|
472 | }
|
473 |
|
474 |
|
475 |
|
476 | if (parent != null && parent.filename) {
|
477 | if (request[0] === '#') {
|
478 | const pkg = readPackageScope(parent.filename) || {};
|
479 |
|
480 |
|
481 |
|
482 | if (pkg.data != null && pkg.data.imports != null) {
|
483 | try {
|
484 | return finalizeEsmResolution(
|
485 | packageImportsResolve(request, pathToFileURL(parent.filename),
|
486 | cjsConditions), parent.filename,
|
487 | pkg.path);
|
488 | } catch (e) {
|
489 | if (e.code === 'ERR_MODULE_NOT_FOUND')
|
490 | throw createEsmNotFoundErr(request);
|
491 | throw e;
|
492 | }
|
493 | }
|
494 | }
|
495 | }
|
496 |
|
497 |
|
498 | const parentPath = trySelfParentPath(parent);
|
499 | const selfResolved = trySelf(parentPath, request);
|
500 | if (selfResolved) {
|
501 | const cacheKey = request + '\x00' +
|
502 | (paths.length === 1 ? paths[0] : ArrayPrototypeJoin(paths, '\x00'));
|
503 | Module._pathCache[cacheKey] = selfResolved;
|
504 | return selfResolved;
|
505 | }
|
506 |
|
507 |
|
508 | const filename = Module._findPath(request, paths, isMain, false);
|
509 | if (filename) return filename;
|
510 | const requireStack = [];
|
511 | for (let cursor = parent;
|
512 | cursor;
|
513 | cursor = moduleParentCache.get(cursor)) {
|
514 | ArrayPrototypePush(requireStack, cursor.filename || cursor.id);
|
515 | }
|
516 | let message = `Cannot find module '${request}'`;
|
517 | if (requireStack.length > 0) {
|
518 | message = message + '\nRequire stack:\n- ' +
|
519 | ArrayPrototypeJoin(requireStack, '\n- ');
|
520 | }
|
521 |
|
522 | const err = new Error(message);
|
523 | err.code = 'MODULE_NOT_FOUND';
|
524 | err.requireStack = requireStack;
|
525 | throw err;
|
526 | };
|
527 |
|
528 | function finalizeEsmResolution(resolved, parentPath, pkgPath) {
|
529 | if (RegExpPrototypeTest(encodedSepRegEx, resolved))
|
530 | throw new ERR_INVALID_MODULE_SPECIFIER(
|
531 | resolved, 'must not include encoded "/" or "\\" characters', parentPath);
|
532 | const filename = fileURLToPath(resolved);
|
533 | const actual = tryReplacementExtensions(filename) || tryFile(filename);
|
534 | if (actual)
|
535 | return actual;
|
536 | const err = createEsmNotFoundErr(filename,
|
537 | path.resolve(pkgPath, 'package.json'));
|
538 | throw err;
|
539 | }
|
540 |
|
541 | function createEsmNotFoundErr(request, path) {
|
542 |
|
543 | const err = new Error(`Cannot find module '${request}'`);
|
544 | err.code = 'MODULE_NOT_FOUND';
|
545 | if (path)
|
546 | err.path = path;
|
547 |
|
548 | return err;
|
549 | }
|
550 |
|
551 |
|
552 | return {
|
553 | Module_findPath,
|
554 | Module_resolveFilename
|
555 | }
|
556 |
|
557 | }
|
558 |
|
559 |
|
560 |
|
561 |
|
562 |
|
563 |
|
564 |
|
565 |
|
566 | function assertScriptCanLoadAsCJSImpl(service, module, filename) {
|
567 | const pkg = readPackageScope(filename);
|
568 |
|
569 |
|
570 | const tsNodeClassification = service.moduleTypeClassifier.classifyModuleByModuleTypeOverrides(normalizeSlashes(filename));
|
571 | if(tsNodeClassification.moduleType === 'cjs') return;
|
572 |
|
573 |
|
574 |
|
575 | const lastDotIndex = filename.lastIndexOf('.');
|
576 | const ext = lastDotIndex >= 0 ? filename.slice(lastDotIndex) : '';
|
577 |
|
578 | if((ext === '.cts' || ext === '.cjs') && tsNodeClassification.moduleType === 'auto') return;
|
579 |
|
580 |
|
581 | if (ext === '.mts' || ext === '.mjs' || tsNodeClassification.moduleType === 'esm' || (pkg && pkg.data && pkg.data.type === 'module')) {
|
582 | const parentPath = module.parent && module.parent.filename;
|
583 | const packageJsonPath = pkg ? path.resolve(pkg.path, 'package.json') : null;
|
584 | throw createErrRequireEsm(filename, parentPath, packageJsonPath);
|
585 | }
|
586 | }
|
587 |
|
588 |
|
589 | module.exports = {
|
590 | createCjsLoader,
|
591 | assertScriptCanLoadAsCJSImpl,
|
592 | readPackageScope
|
593 | };
|