| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent c7e57f5 commit b373202
13 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1255,6 +1255,18 @@ passing a second `parentURL` argument for contextual resolution. | |||
| 1255 | 1255 | ||
| 1256 | 1256 | Previously gated the entire `import.meta.resolve` feature. | |
| 1257 | 1257 | ||
| 1258 | + ### `--experimental-import-text` | ||
| 1259 | + | ||
| 1260 | + <!-- YAML | ||
| 1261 | + added: | ||
| 1262 | + - REPLACEME | ||
| 1263 | + --> | ||
| 1264 | + | ||
| 1265 | + > Stability: 1.0 - Early development | ||
| 1266 | + | ||
| 1267 | + Enable experimental support for importing modules with | ||
| 1268 | + `with { type: 'text' }`. | ||
| 1269 | + | ||
| 1258 | 1270 | ### `--experimental-inspector-network-resource` | |
| 1259 | 1271 | ||
| 1260 | 1272 | <!-- YAML | |
@@ -3781,6 +3793,7 @@ one is included in the list below. | |||
| 3781 | 3793 | * `--experimental-eventsource` | |
| 3782 | 3794 | * `--experimental-ffi` | |
| 3783 | 3795 | * `--experimental-import-meta-resolve` | |
| 3796 | + * `--experimental-import-text` | ||
| 3784 | 3797 | * `--experimental-json-modules` | |
| 3785 | 3798 | * `--experimental-loader` | |
| 3786 | 3799 | * `--experimental-modules` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -294,8 +294,10 @@ Node.js only supports the `type` attribute, for which it supports the following | |||
| 294 | 294 | | Attribute `type` | Needed for | | |
| 295 | 295 | | ---------------- | ---------------- | | |
| 296 | 296 | | `'json'` | [JSON modules][] | | |
| 297 | + | `'text'` | [Text modules][] | | ||
| 297 | 298 | ||
| 298 | 299 | The `type: 'json'` attribute is mandatory when importing JSON modules. | |
| 300 | + The `type: 'text'` attribute is mandatory when importing text modules. | ||
| 299 | 301 | ||
| 300 | 302 | ## Built-in modules | |
| 301 | 303 | ||
@@ -707,6 +709,23 @@ exports. A cache entry is created in the CommonJS cache to avoid duplication. | |||
| 707 | 709 | The same object is returned in CommonJS if the JSON module has already been | |
| 708 | 710 | imported from the same path. | |
| 709 | 711 | ||
| 712 | + ## Text modules | ||
| 713 | + | ||
| 714 | + > Stability: 1.0 - Early development | ||
| 715 | + | ||
| 716 | + Text modules are available behind the `--experimental-import-text` flag. | ||
| 717 | + | ||
| 718 | + Text files can be referenced by `import`: | ||
| 719 | + | ||
| 720 | + ```js | ||
| 721 | + import message from './message.txt' with { type: 'text' }; | ||
| 722 | + ``` | ||
| 723 | + | ||
| 724 | + The `with { type: 'text' }` syntax is mandatory; see [Import Attributes][]. | ||
| 725 | + | ||
| 726 | + The imported text only exposes a `default` export whose value is the module | ||
| 727 | + source as a string. | ||
| 728 | + | ||
| 710 | 729 | <i id="esm_experimental_wasm_modules"></i> | |
| 711 | 730 | ||
| 712 | 731 | ## Wasm modules | |
@@ -1313,6 +1332,7 @@ resolution for ESM specifiers is [commonjs-extension-resolution-loader][]. | |||
| 1313 | 1332 | [Package maps]: packages.md#package-maps | |
| 1314 | 1333 | [Source Phase Imports]: https://github.com/tc39/proposal-source-phase-imports | |
| 1315 | 1334 | [Terminology]: #terminology | |
| 1335 | + [Text modules]: #text-modules | ||
| 1316 | 1336 | [URL]: https://url.spec.whatwg.org/ | |
| 1317 | 1337 | [WebAssembly JS String Builtins Proposal]: https://github.com/WebAssembly/js-string-builtins | |
| 1318 | 1338 | [`"exports"`]: packages.md#exports | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,6 +8,7 @@ const { | |||
| 8 | 8 | ObjectValues, | |
| 9 | 9 | } = primordials; | |
| 10 | 10 | const { validateString } = require('internal/validators'); | |
| 11 | + const { getOptionValue } = require('internal/options'); | ||
| 11 | 12 | ||
| 12 | 13 | const { | |
| 13 | 14 | ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE, | |
@@ -29,8 +30,13 @@ const formatTypeMap = { | |||
| 29 | 30 | 'commonjs': kImplicitTypeAttribute, | |
| 30 | 31 | 'json': 'json', | |
| 31 | 32 | 'module': kImplicitTypeAttribute, | |
| 33 | + 'text': 'text', | ||
| 32 | 34 | '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 | |
| 33 | 35 | }; | |
| 36 | + // NOTE: Don't add bytes support yet as it requires Uint8Arrays backed by immutable ArrayBuffers, | ||
| 37 | + // which V8 does not support yet. | ||
| 38 | + // see: https://github.com/nodejs/node/pull/62300#issuecomment-4079163816 | ||
| 39 | + | ||
| 34 | 40 | ||
| 35 | 41 | /** | |
| 36 | 42 | * The HTML spec disallows the default type to be explicitly specified | |
@@ -42,7 +48,6 @@ const supportedTypeAttributes = ArrayPrototypeFilter( | |||
| 42 | 48 | ObjectValues(formatTypeMap), | |
| 43 | 49 | (type) => type !== kImplicitTypeAttribute); | |
| 44 | 50 | ||
| 45 | - | ||
| 46 | 51 | /** | |
| 47 | 52 | * Test a module's import attributes. | |
| 48 | 53 | * @param {string} url The URL of the imported module, for error reporting. | |
@@ -62,6 +67,12 @@ function validateAttributes(url, format, | |||
| 62 | 67 | } | |
| 63 | 68 | const validType = formatTypeMap[format]; | |
| 64 | 69 | ||
| 70 | + if (validType !== undefined && | ||
| 71 | + importAttributes.type === 'text' && | ||
| 72 | + !getOptionValue('--experimental-import-text')) { | ||
| 73 | + throw new ERR_IMPORT_ATTRIBUTE_UNSUPPORTED('type', importAttributes.type, url); | ||
| 74 | + } | ||
| 75 | + | ||
| 65 | 76 | switch (validType) { | |
| 66 | 77 | case undefined: | |
| 67 | 78 | // Ignore attributes for module formats we don't recognize, to allow new | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -47,6 +47,13 @@ function mimeToFormat(mime) { | |||
| 47 | 47 | ) { return 'module'; } | |
| 48 | 48 | if (mime === 'application/json') { return 'json'; } | |
| 49 | 49 | if (mime === 'application/wasm') { return 'wasm'; } | |
| 50 | + if ( | ||
| 51 | + getOptionValue('--experimental-import-text') && | ||
| 52 | + RegExpPrototypeExec( | ||
| 53 | + /^\s*text\/plain\s*(;\s*charset=utf-?8\s*)?$/i, | ||
| 54 | + mime, | ||
| 55 | + ) !== null | ||
| 56 | + ) { return 'text'; } | ||
| 50 | 57 | return null; | |
| 51 | 58 | } | |
| 52 | 59 | ||
@@ -236,12 +243,22 @@ function getFileProtocolModuleFormat(url, context = { __proto__: null }, ignoreE | |||
| 236 | 243 | throw new ERR_UNKNOWN_FILE_EXTENSION(ext, filepath); | |
| 237 | 244 | } | |
| 238 | 245 | ||
| 246 | + // If the caller explicitly requests text format via import attributes, honor it regardless of file extension. | ||
| 247 | + function isExperimentalTextImport(importAttributes) { | ||
| 248 | + return getOptionValue('--experimental-import-text') && | ||
| 249 | + importAttributes?.type === 'text'; | ||
| 250 | + } | ||
| 251 | + | ||
| 239 | 252 | /** | |
| 240 | 253 | * @param {URL} url | |
| 241 | - * @param {{parentURL: string}} context | ||
| 254 | + * @param {{parentURL: string, importAttributes?: Record<string, string>}} context | ||
| 242 | 255 | * @returns {Promise<string> | string | undefined} only works when enabled | |
| 243 | 256 | */ | |
| 244 | 257 | function defaultGetFormatWithoutErrors(url, context) { | |
| 258 | + if (isExperimentalTextImport(context?.importAttributes)) { | ||
| 259 | + return 'text'; | ||
| 260 | + } | ||
| 261 | + | ||
| 245 | 262 | const protocol = url.protocol; | |
| 246 | 263 | if (!ObjectPrototypeHasOwnProperty(protocolHandlers, protocol)) { | |
| 247 | 264 | return null; | |
@@ -251,10 +268,14 @@ function defaultGetFormatWithoutErrors(url, context) { | |||
| 251 | 268 | ||
| 252 | 269 | /** | |
| 253 | 270 | * @param {URL} url | |
| 254 | - * @param {{parentURL: string}} context | ||
| 271 | + * @param {{parentURL: string, importAttributes?: Record<string, string>}} context | ||
| 255 | 272 | * @returns {Promise<string> | string | undefined} only works when enabled | |
| 256 | 273 | */ | |
| 257 | 274 | function defaultGetFormat(url, context) { | |
| 275 | + if (isExperimentalTextImport(context?.importAttributes)) { | ||
| 276 | + return 'text'; | ||
| 277 | + } | ||
| 278 | + | ||
| 258 | 279 | const protocol = url.protocol; | |
| 259 | 280 | if (!ObjectPrototypeHasOwnProperty(protocolHandlers, protocol)) { | |
| 260 | 281 | return null; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -99,7 +99,7 @@ const { defaultLoadSync, throwUnknownModuleFormat } = require('internal/modules/ | |||
| 99 | 99 | */ | |
| 100 | 100 | ||
| 101 | 101 | /** | |
| 102 | - * @typedef {'builtin'|'commonjs'|'json'|'module'|'wasm'} ModuleFormat | ||
| 102 | + * @typedef {'builtin'|'commonjs'|'json'|'module'|'text'|'wasm'} ModuleFormat | ||
| 103 | 103 | */ | |
| 104 | 104 | ||
| 105 | 105 | /** | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -681,3 +681,14 @@ translators.set('module-typescript', function(url, translateContext, parentURL) | |||
| 681 | 681 | translateContext.source = stripTypeScriptModuleTypes(stringify(source), url); | |
| 682 | 682 | return FunctionPrototypeCall(translators.get('module'), this, url, translateContext, parentURL); | |
| 683 | 683 | }); | |
| 684 | + | ||
| 685 | + // Strategy for loading source as text. | ||
| 686 | + translators.set('text', function textStrategy(url, translateContext) { | ||
| 687 | + emitExperimentalWarning('Text import'); | ||
| 688 | + let { source } = translateContext; | ||
| 689 | + assertBufferSource(source, true, 'load'); | ||
| 690 | + source = stringify(source); | ||
| 691 | + return new ModuleWrap(url, undefined, ['default'], function() { | ||
| 692 | + this.setExport('default', source); | ||
| 693 | + }); | ||
| 694 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -647,6 +647,11 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { | |||
| 647 | 647 | AddAlias("--loader", "--experimental-loader"); | |
| 648 | 648 | AddOption("--experimental-modules", "", NoOp{}, kAllowedInEnvvar); | |
| 649 | 649 | AddOption("--experimental-wasm-modules", "", NoOp{}, kAllowedInEnvvar); | |
| 650 | + AddOption("--experimental-import-text", | ||
| 651 | + "experimental support for importing source as text with import " | ||
| 652 | + "attributes", | ||
| 653 | + &EnvironmentOptions::experimental_import_text, | ||
| 654 | + kAllowedInEnvvar); | ||
| 650 | 655 | AddOption("--experimental-import-meta-resolve", | |
| 651 | 656 | "experimental ES Module import.meta.resolve() parentURL support", | |
| 652 | 657 | &EnvironmentOptions::experimental_import_meta_resolve, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -138,6 +138,7 @@ class EnvironmentOptions : public Options { | |||
| 138 | 138 | std::string localstorage_file; | |
| 139 | 139 | bool experimental_global_navigator = true; | |
| 140 | 140 | bool experimental_global_web_crypto = true; | |
| 141 | + bool experimental_import_text = EXPERIMENTALS_DEFAULT_VALUE; | ||
| 141 | 142 | bool experimental_import_meta_resolve = EXPERIMENTALS_DEFAULT_VALUE; | |
| 142 | 143 | std::string input_type; // Value of --input-type | |
| 143 | 144 | bool entry_is_url = false; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -26,6 +26,11 @@ async function test() { | |||
| 26 | 26 | { code: 'ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE' } | |
| 27 | 27 | ); | |
| 28 | 28 | ||
| 29 | + await assert.rejects( | ||
| 30 | + import(jsModuleDataUrl, { with: { type: 'text' } }), | ||
| 31 | + { code: 'ERR_IMPORT_ATTRIBUTE_UNSUPPORTED' } | ||
| 32 | + ); | ||
| 33 | + | ||
| 29 | 34 | await assert.rejects( | |
| 30 | 35 | import(jsModuleDataUrl, { with: { type: 'json', other: 'unsupported' } }), | |
| 31 | 36 | { code: 'ERR_IMPORT_ATTRIBUTE_UNSUPPORTED' } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -21,6 +21,11 @@ await assert.rejects( | |||
| 21 | 21 | { code: 'ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE' } | |
| 22 | 22 | ); | |
| 23 | 23 | ||
| 24 | + await assert.rejects( | ||
| 25 | + import(jsModuleDataUrl, { with: { type: 'text' } }), | ||
| 26 | + { code: 'ERR_IMPORT_ATTRIBUTE_UNSUPPORTED' } | ||
| 27 | + ); | ||
| 28 | + | ||
| 24 | 29 | await assert.rejects( | |
| 25 | 30 | import(jsModuleDataUrl, { with: { type: 'json', other: 'unsupported' } }), | |
| 26 | 31 | { code: 'ERR_IMPORT_ATTRIBUTE_UNSUPPORTED' } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments