diff --git a/lib/internal/modules/esm/assert.js b/lib/internal/modules/esm/assert.js index 406c0f4e4513..9bd6967dbbbe 100644 --- a/lib/internal/modules/esm/assert.js +++ b/lib/internal/modules/esm/assert.js @@ -3,6 +3,7 @@ const { ArrayPrototypeFilter, ArrayPrototypeIncludes, + ArrayPrototypePush, ObjectKeys, ObjectPrototypeHasOwnProperty, ObjectValues, @@ -30,7 +31,6 @@ const formatTypeMap = { 'commonjs': kImplicitTypeAttribute, 'json': 'json', 'module': kImplicitTypeAttribute, - 'text': 'text', 'wasm': kImplicitTypeAttribute, // It's unclear whether the HTML spec will require an type attribute or not for Wasm; see https://github.com/WebAssembly/esm-integration/issues/42 }; // NOTE: Don't add bytes support yet as it requires Uint8Arrays backed by immutable ArrayBuffers, @@ -48,6 +48,21 @@ const supportedTypeAttributes = ArrayPrototypeFilter( ObjectValues(formatTypeMap), (type) => type !== kImplicitTypeAttribute); +let importAttributesInitialized = false; + +function initializeImportAttributes() { + if (importAttributesInitialized) { + return; + } + + importAttributesInitialized = true; + + if (getOptionValue('--experimental-import-text')) { + formatTypeMap.text = 'text'; + ArrayPrototypePush(supportedTypeAttributes, 'text'); + } +} + /** * Test a module's import attributes. * @param {string} url The URL of the imported module, for error reporting. @@ -59,6 +74,8 @@ const supportedTypeAttributes = ArrayPrototypeFilter( */ function validateAttributes(url, format, importAttributes = { __proto__: null }) { + initializeImportAttributes(); + const keys = ObjectKeys(importAttributes); for (let i = 0; i < keys.length; i++) { if (keys[i] !== 'type') { @@ -67,12 +84,6 @@ function validateAttributes(url, format, } const validType = formatTypeMap[format]; - if (validType !== undefined && - importAttributes.type === 'text' && - !getOptionValue('--experimental-import-text')) { - throw new ERR_IMPORT_ATTRIBUTE_UNSUPPORTED('type', importAttributes.type, url); - } - switch (validType) { case undefined: // Ignore attributes for module formats we don't recognize, to allow new diff --git a/test/es-module/test-esm-loader-text-format.mjs b/test/es-module/test-esm-loader-text-format.mjs new file mode 100644 index 000000000000..2a35992dbcf4 --- /dev/null +++ b/test/es-module/test-esm-loader-text-format.mjs @@ -0,0 +1,23 @@ +import '../common/index.mjs'; +import assert from 'node:assert'; +import { registerHooks } from 'node:module'; + +// A user loader can use `text` with and without import attributes without the feature flag. + +registerHooks({ + load(url, context, nextLoad) { + if (url.endsWith('.txt')) { + return nextLoad(url, { ...context, format: 'text' }); + } + return nextLoad(url, context); + }, +}); + +const { default: text } = await import('../fixtures/file-to-read-without-bom.txt'); +const { default: empty } = await import( + '../fixtures/empty.txt', + { with: { type: 'text' } } +); + +assert.strictEqual(text, 'abc\ndef\nghi\n'); +assert.strictEqual(empty, '');