Skip to content

Commit 67ecb10

Browse files
module: fix discrepancy between .ts and .js
PR-URL: #54461 Backport-PR-URL: #54566 Fixes: #54457 Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Zeyu "Alex" Yang <himself65@outlook.com>
1 parent 8a3482e commit 67ecb10

File tree

6 files changed

+83
-56
lines changed

6 files changed

+83
-56
lines changed

lib/internal/modules/esm/get_format.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,14 @@ function getFileProtocolModuleFormat(url, context = { __proto__: null }, ignoreE
161161
default: { // The user did not pass `--experimental-default-type`.
162162
// `source` is undefined when this is called from `defaultResolve`;
163163
// but this gets called again from `defaultLoad`/`defaultLoadSync`.
164-
let parsedSource;
165-
if (source) {
166-
const { stripTypeScriptTypes } = require('internal/modules/helpers');
167-
parsedSource = stripTypeScriptTypes(source, url);
168-
}
164+
// Since experimental-strip-types depends on detect-module, we always return null
165+
// if source is undefined.
166+
if (!source) { return null; }
167+
const { stripTypeScriptTypes, stringify } = require('internal/modules/helpers');
168+
const stringifiedSource = stringify(source);
169+
const parsedSource = stripTypeScriptTypes(stringifiedSource, fileURLToPath(url));
169170
const detectedFormat = detectModuleFormat(parsedSource, url);
170-
// When source is undefined, default to module-typescript.
171-
const format = detectedFormat ? `${detectedFormat}-typescript` : 'module-typescript';
171+
const format = `${detectedFormat}-typescript`;
172172
if (format === 'module-typescript' && foundPackageJson) {
173173
// This module has a .js extension, a package.json with no `type` field, and ESM syntax.
174174
// Warn about the missing `type` field so that the user can avoid the performance penalty of detection.

lib/internal/modules/esm/translators.js

Lines changed: 2 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,6 @@ const {
1818
globalThis: { WebAssembly },
1919
} = primordials;
2020

21-
/** @type {import('internal/util/types')} */
22-
let _TYPES = null;
23-
/**
24-
* Lazily loads and returns the internal/util/types module.
25-
*/
26-
function lazyTypes() {
27-
if (_TYPES !== null) { return _TYPES; }
28-
return _TYPES = require('internal/util/types');
29-
}
30-
3121
const {
3222
compileFunctionForCJSLoader,
3323
} = internalBinding('contextify');
@@ -37,7 +27,9 @@ const assert = require('internal/assert');
3727
const { readFileSync } = require('fs');
3828
const { dirname, extname, isAbsolute } = require('path');
3929
const {
30+
assertBufferSource,
4031
loadBuiltinModule,
32+
stringify,
4133
stripTypeScriptTypes,
4234
stripBOM,
4335
urlToFilename,
@@ -57,7 +49,6 @@ let debug = require('internal/util/debuglog').debuglog('esm', (fn) => {
5749
const { emitExperimentalWarning, kEmptyObject, setOwnProperty, isWindows } = require('internal/util');
5850
const {
5951
ERR_UNKNOWN_BUILTIN_MODULE,
60-
ERR_INVALID_RETURN_PROPERTY_VALUE,
6152
} = require('internal/errors').codes;
6253
const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache');
6354
const moduleWrap = internalBinding('module_wrap');
@@ -107,44 +98,6 @@ function initCJSParseSync() {
10798
const translators = new SafeMap();
10899
exports.translators = translators;
109100

110-
let DECODER = null;
111-
/**
112-
* Asserts that the given body is a buffer source (either a string, array buffer, or typed array).
113-
* Throws an error if the body is not a buffer source.
114-
* @param {string | ArrayBufferView | ArrayBuffer} body - The body to check.
115-
* @param {boolean} allowString - Whether or not to allow a string as a valid buffer source.
116-
* @param {string} hookName - The name of the hook being called.
117-
* @throws {ERR_INVALID_RETURN_PROPERTY_VALUE} If the body is not a buffer source.
118-
*/
119-
function assertBufferSource(body, allowString, hookName) {
120-
if (allowString && typeof body === 'string') {
121-
return;
122-
}
123-
const { isArrayBufferView, isAnyArrayBuffer } = lazyTypes();
124-
if (isArrayBufferView(body) || isAnyArrayBuffer(body)) {
125-
return;
126-
}
127-
throw new ERR_INVALID_RETURN_PROPERTY_VALUE(
128-
`${allowString ? 'string, ' : ''}array buffer, or typed array`,
129-
hookName,
130-
'source',
131-
body,
132-
);
133-
}
134-
135-
/**
136-
* Converts a buffer or buffer-like object to a string.
137-
* @param {string | ArrayBuffer | ArrayBufferView} body - The buffer or buffer-like object to convert to a string.
138-
* @returns {string} The resulting string.
139-
*/
140-
function stringify(body) {
141-
if (typeof body === 'string') { return body; }
142-
assertBufferSource(body, false, 'load');
143-
const { TextDecoder } = require('internal/encoding');
144-
DECODER = DECODER === null ? new TextDecoder() : DECODER;
145-
return DECODER.decode(body);
146-
}
147-
148101
/**
149102
* Converts a URL to a file path if the URL protocol is 'file:'.
150103
* @param {string} url - The URL to convert.

lib/internal/modules/helpers.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const {
1616
} = primordials;
1717
const {
1818
ERR_INVALID_ARG_TYPE,
19+
ERR_INVALID_RETURN_PROPERTY_VALUE,
1920
} = require('internal/errors').codes;
2021
const { BuiltinModule } = require('internal/bootstrap/realm');
2122

@@ -429,10 +430,60 @@ function getCompileCacheDir() {
429430
return _getCompileCacheDir() || undefined;
430431
}
431432

433+
/** @type {import('internal/util/types')} */
434+
let _TYPES = null;
435+
/**
436+
* Lazily loads and returns the internal/util/types module.
437+
*/
438+
function lazyTypes() {
439+
if (_TYPES !== null) { return _TYPES; }
440+
return _TYPES = require('internal/util/types');
441+
}
442+
443+
/**
444+
* Asserts that the given body is a buffer source (either a string, array buffer, or typed array).
445+
* Throws an error if the body is not a buffer source.
446+
* @param {string | ArrayBufferView | ArrayBuffer} body - The body to check.
447+
* @param {boolean} allowString - Whether or not to allow a string as a valid buffer source.
448+
* @param {string} hookName - The name of the hook being called.
449+
* @throws {ERR_INVALID_RETURN_PROPERTY_VALUE} If the body is not a buffer source.
450+
*/
451+
function assertBufferSource(body, allowString, hookName) {
452+
if (allowString && typeof body === 'string') {
453+
return;
454+
}
455+
const { isArrayBufferView, isAnyArrayBuffer } = lazyTypes();
456+
if (isArrayBufferView(body) || isAnyArrayBuffer(body)) {
457+
return;
458+
}
459+
throw new ERR_INVALID_RETURN_PROPERTY_VALUE(
460+
`${allowString ? 'string, ' : ''}array buffer, or typed array`,
461+
hookName,
462+
'source',
463+
body,
464+
);
465+
}
466+
467+
let DECODER = null;
468+
469+
/**
470+
* Converts a buffer or buffer-like object to a string.
471+
* @param {string | ArrayBuffer | ArrayBufferView} body - The buffer or buffer-like object to convert to a string.
472+
* @returns {string} The resulting string.
473+
*/
474+
function stringify(body) {
475+
if (typeof body === 'string') { return body; }
476+
assertBufferSource(body, false, 'load');
477+
const { TextDecoder } = require('internal/encoding');
478+
DECODER = DECODER === null ? new TextDecoder() : DECODER;
479+
return DECODER.decode(body);
480+
}
481+
432482
module.exports = {
433483
addBuiltinLibsToObject,
434484
constants,
435485
enableCompileCache,
486+
assertBufferSource,
436487
getBuiltinModule,
437488
getCjsConditions,
438489
getCompileCacheDir,
@@ -442,6 +493,7 @@ module.exports = {
442493
makeRequireFunction,
443494
normalizeReferrerURL,
444495
stripTypeScriptTypes,
496+
stringify,
445497
stripBOM,
446498
toRealPath,
447499
hasStartedUserCJSExecution() {

test/es-module/test-typescript.mjs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,3 +325,14 @@ test('execute a TypeScript file with CommonJS syntax requiring .mts with require
325325
match(result.stdout, /Hello, TypeScript!/);
326326
strictEqual(result.code, 0);
327327
});
328+
329+
test('execute a JavaScript file importing a cjs TypeScript file', async () => {
330+
const result = await spawnPromisified(process.execPath, [
331+
'--experimental-strip-types',
332+
'--no-warnings',
333+
fixtures.path('typescript/ts/issue-54457.mjs'),
334+
]);
335+
strictEqual(result.stderr, '');
336+
match(result.stdout, /Hello, TypeScript!/);
337+
strictEqual(result.code, 0);
338+
});
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// https://github.com/nodejs/node/issues/54457
2+
const { text } = await import('./test-require.ts');
3+
4+
console.log(text);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const util = require('node:util');
2+
3+
const text = 'Hello, TypeScript!';
4+
5+
module.exports = {
6+
text
7+
};

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy