Skip to content

module: refactor commonjs typescript loader #58657

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 19 additions & 94 deletions lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -453,17 +453,6 @@ function initializeCJS() {
// TODO(joyeecheung): deprecate this in favor of a proper hook?
Module.runMain =
require('internal/modules/run_main').executeUserEntryPoint;

const tsEnabled = getOptionValue('--experimental-strip-types');
if (tsEnabled) {
Module._extensions['.cts'] = loadCTS;
Module._extensions['.ts'] = loadTS;
}
if (getOptionValue('--experimental-require-module')) {
if (tsEnabled) {
Module._extensions['.mts'] = loadMTS;
}
}
}

// Given a module name, and a list of paths to test, returns the first
Expand Down Expand Up @@ -669,31 +658,6 @@ function resolveExports(nmPath, request, conditions) {
}
}

// We don't cache this in case user extends the extensions.
function getDefaultExtensions() {
let extensions = ObjectKeys(Module._extensions);
const tsEnabled = getOptionValue('--experimental-strip-types');
if (tsEnabled) {
// remove .ts and .cts from the default extensions
// to avoid extensionless require of .ts and .cts files.
extensions = ArrayPrototypeFilter(extensions, (ext) =>
(ext !== '.ts' || Module._extensions['.ts'] !== loadTS) &&
(ext !== '.cts' || Module._extensions['.cts'] !== loadCTS),
);
}

if (!getOptionValue('--experimental-require-module')) {
return extensions;
}

if (tsEnabled) {
extensions = ArrayPrototypeFilter(extensions, (ext) =>
ext !== '.mts' || Module._extensions['.mts'] !== loadMTS,
);
}
return extensions;
}

/**
* Get the absolute path to a module.
* @param {string} request Relative or absolute file path
Expand Down Expand Up @@ -785,7 +749,7 @@ Module._findPath = function(request, paths, isMain, conditions = getCjsCondition
if (!filename) {
// Try it with each of the extensions
if (exts === undefined) {
exts = getDefaultExtensions();
exts = ObjectKeys(Module._extensions);
}
filename = tryExtensions(basePath, exts, isMain);
}
Expand All @@ -794,7 +758,7 @@ Module._findPath = function(request, paths, isMain, conditions = getCjsCondition
if (!filename && rc === 1) { // Directory.
// try it with each of the extensions at "index"
if (exts === undefined) {
exts = getDefaultExtensions();
exts = ObjectKeys(Module._extensions);
}
filename = tryPackage(basePath, exts, isMain, request);
}
Expand Down Expand Up @@ -1459,12 +1423,6 @@ Module.prototype.load = function(filename) {

const extension = findLongestRegisteredExtension(filename);

if (getOptionValue('--experimental-strip-types')) {
if (StringPrototypeEndsWith(filename, '.mts') && !Module._extensions['.mts']) {
throw new ERR_REQUIRE_ESM(filename, true);
}
}

Module._extensions[extension](this, filename);
this.loaded = true;

Expand Down Expand Up @@ -1776,55 +1734,6 @@ function loadSource(mod, filename, formatFromNode) {
return { source: mod[kModuleSource], format: mod[kFormat] };
}

/**
* Built-in handler for `.mts` files.
* @param {Module} mod CJS module instance
* @param {string} filename The file path of the module
*/
function loadMTS(mod, filename) {
const loadResult = loadSource(mod, filename, 'module-typescript');
mod._compile(loadResult.source, filename, loadResult.format);
}

/**
* Built-in handler for `.cts` files.
* @param {Module} module CJS module instance
* @param {string} filename The file path of the module
*/
function loadCTS(module, filename) {
const loadResult = loadSource(module, filename, 'commonjs-typescript');
module._compile(loadResult.source, filename, loadResult.format);
}

/**
* Built-in handler for `.ts` files.
* @param {Module} module CJS module instance
* @param {string} filename The file path of the module
*/
function loadTS(module, filename) {
const pkg = packageJsonReader.getNearestParentPackageJSON(filename);
const typeFromPjson = pkg?.data.type;

let format;
if (typeFromPjson === 'module') {
format = 'module-typescript';
} else if (typeFromPjson === 'commonjs') {
format = 'commonjs-typescript';
} else {
format = 'typescript';
}
const loadResult = loadSource(module, filename, format);

// Function require shouldn't be used in ES modules when require(esm) is disabled.
if (typeFromPjson === 'module' && !getOptionValue('--experimental-require-module')) {
const err = getRequireESMError(module, pkg, loadResult.source, filename);
throw err;
}

module[kFormat] = loadResult.format;
module._compile(loadResult.source, filename, loadResult.format);
};

function reconstructErrorStack(err, parentPath, parentSource) {
const errLine = StringPrototypeSplit(
StringPrototypeSlice(err.stack, StringPrototypeIndexOf(
Expand Down Expand Up @@ -1878,6 +1787,7 @@ function getRequireESMError(mod, pkg, content, filename) {
*/
Module._extensions['.js'] = function(module, filename) {
let format, pkg;
const tsEnabled = getOptionValue('--experimental-strip-types');
if (StringPrototypeEndsWith(filename, '.cjs')) {
format = 'commonjs';
} else if (StringPrototypeEndsWith(filename, '.mjs')) {
Expand All @@ -1888,10 +1798,25 @@ Module._extensions['.js'] = function(module, filename) {
if (typeFromPjson === 'module' || typeFromPjson === 'commonjs' || !typeFromPjson) {
format = typeFromPjson;
}
} else if (StringPrototypeEndsWith(filename, '.mts') && tsEnabled) {
format = 'module-typescript';
} else if (StringPrototypeEndsWith(filename, '.cts') && tsEnabled) {
format = 'commonjs-typescript';
} else if (StringPrototypeEndsWith(filename, '.ts') && tsEnabled) {
pkg = packageJsonReader.getNearestParentPackageJSON(filename);
const typeFromPjson = pkg?.data.type;
if (typeFromPjson === 'module') {
format = 'module-typescript';
} else if (typeFromPjson === 'commonjs') {
format = 'commonjs-typescript';
} else {
format = 'typescript';
}
}
const { source, format: loadedFormat } = loadSource(module, filename, format);
// Function require shouldn't be used in ES modules when require(esm) is disabled.
if (loadedFormat === 'module' && !getOptionValue('--experimental-require-module')) {
if ((loadedFormat === 'module' || loadedFormat === 'module-typescript') &&
!getOptionValue('--experimental-require-module')) {
const err = getRequireESMError(module, pkg, source, filename);
throw err;
}
Expand Down
Loading