| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 70d025f commit d09f6d5
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1170,16 +1170,27 @@ export async function resolve(specifier, context, defaultResolve) { | |||
| 1170 | 1170 | > signature may change. Do not rely on the API described below. | |
| 1171 | 1171 | ||
| 1172 | 1172 | The `getFormat` hook provides a way to define a custom method of determining how | |
| 1173 | - a URL should be interpreted. This can be one of the following: | ||
| 1173 | + a URL should be interpreted. The `format` returned also affects what the | ||
| 1174 | + acceptable forms of source values are for a module when parsing. This can be one | ||
| 1175 | + of the following: | ||
| 1174 | 1176 | ||
| 1175 | - | `format` | Description | | ||
| 1176 | - | --- | --- | | ||
| 1177 | - | `'builtin'` | Load a Node.js builtin module | | ||
| 1178 | - | `'commonjs'` | Load a Node.js CommonJS module | | ||
| 1179 | - | `'dynamic'` | Use a [dynamic instantiate hook][] | | ||
| 1180 | - | `'json'` | Load a JSON file | | ||
| 1181 | - | `'module'` | Load a standard JavaScript module (ES module) | | ||
| 1182 | - | `'wasm'` | Load a WebAssembly module | | ||
| 1177 | + | `format` | Description | Acceptable Types For `source` Returned by `getSource` or `transformSource` | | ||
| 1178 | + | --- | --- | --- | | ||
| 1179 | + | `'builtin'` | Load a Node.js builtin module | Not applicable | | ||
| 1180 | + | `'commonjs'` | Load a Node.js CommonJS module | Not applicable | | ||
| 1181 | + | `'dynamic'` | Use a [dynamic instantiate hook][] | Not applicable | | ||
| 1182 | + | `'json'` | Load a JSON file | { [ArrayBuffer][], [string][], [TypedArray][] } | | ||
| 1183 | + | `'module'` | Load an ES module | { [ArrayBuffer][], [string][], [TypedArray][] } | | ||
| 1184 | + | `'wasm'` | Load a WebAssembly module | { [ArrayBuffer][], [string][], [TypedArray][] } | | ||
| 1185 | + | ||
| 1186 | + Note: These types all correspond to classes defined in ECMAScript. | ||
| 1187 | + | ||
| 1188 | + * The specific [ArrayBuffer][] object is a [SharedArrayBuffer][]. | ||
| 1189 | + * The specific [string][] object is not the class constructor, but an instance. | ||
| 1190 | + * The specific [TypedArray][] object is a [Uint8Array][]. | ||
| 1191 | + | ||
| 1192 | + Note: If the source value of a text-based format (i.e., `'json'`, `'module'`) is | ||
| 1193 | + not a string, it will be converted to a string using [`util.TextDecoder`][]. | ||
| 1183 | 1194 | ||
| 1184 | 1195 | ```js | |
| 1185 | 1196 | /** | |
@@ -1819,6 +1830,12 @@ success! | |||
| 1819 | 1830 | [`module.createRequire()`]: modules.html#modules_module_createrequire_filename | |
| 1820 | 1831 | [`module.syncBuiltinESMExports()`]: modules.html#modules_module_syncbuiltinesmexports | |
| 1821 | 1832 | [`transformSource` hook]: #esm_code_transformsource_code_hook | |
| 1833 | + [ArrayBuffer]: http://www.ecma-international.org/ecma-262/6.0/#sec-arraybuffer-constructor | ||
| 1834 | + [SharedArrayBuffer]: https://tc39.es/ecma262/#sec-sharedarraybuffer-constructor | ||
| 1835 | + [string]: http://www.ecma-international.org/ecma-262/6.0/#sec-string-constructor | ||
| 1836 | + [TypedArray]: http://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects | ||
| 1837 | + [Uint8Array]: http://www.ecma-international.org/ecma-262/6.0/#sec-uint8array | ||
| 1838 | + [`util.TextDecoder`]: util.html#util_class_util_textdecoder | ||
| 1822 | 1839 | [dynamic instantiate hook]: #esm_code_dynamicinstantiate_code_hook | |
| 1823 | 1840 | [import an ES or CommonJS module for its side effects only]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Import_a_module_for_its_side_effects_only | |
| 1824 | 1841 | [special scheme]: https://url.spec.whatwg.org/#special-scheme | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -11,6 +11,12 @@ const { | |||
| 11 | 11 | StringPrototypeReplace, | |
| 12 | 12 | } = primordials; | |
| 13 | 13 | ||
| 14 | + let _TYPES = null; | ||
| 15 | + function lazyTypes() { | ||
| 16 | + if (_TYPES !== null) return _TYPES; | ||
| 17 | + return _TYPES = require('internal/util/types'); | ||
| 18 | + } | ||
| 19 | + | ||
| 14 | 20 | const { | |
| 15 | 21 | stripBOM, | |
| 16 | 22 | loadNativeModule | |
@@ -26,7 +32,10 @@ const createDynamicModule = require( | |||
| 26 | 32 | const { fileURLToPath, URL } = require('url'); | |
| 27 | 33 | const { debuglog } = require('internal/util/debuglog'); | |
| 28 | 34 | const { emitExperimentalWarning } = require('internal/util'); | |
| 29 | - const { ERR_UNKNOWN_BUILTIN_MODULE } = require('internal/errors').codes; | ||
| 35 | + const { | ||
| 36 | + ERR_UNKNOWN_BUILTIN_MODULE, | ||
| 37 | + ERR_INVALID_RETURN_PROPERTY_VALUE | ||
| 38 | + } = require('internal/errors').codes; | ||
| 30 | 39 | const { maybeCacheSourceMap } = require('internal/source_map/source_map_cache'); | |
| 31 | 40 | const moduleWrap = internalBinding('module_wrap'); | |
| 32 | 41 | const { ModuleWrap } = moduleWrap; | |
@@ -39,6 +48,30 @@ const debug = debuglog('esm'); | |||
| 39 | 48 | const translators = new SafeMap(); | |
| 40 | 49 | exports.translators = translators; | |
| 41 | 50 | ||
| 51 | + let DECODER = null; | ||
| 52 | + function assertBufferSource(body, allowString, hookName) { | ||
| 53 | + if (allowString && typeof body === 'string') { | ||
| 54 | + return; | ||
| 55 | + } | ||
| 56 | + const { isArrayBufferView, isAnyArrayBuffer } = lazyTypes(); | ||
| 57 | + if (isArrayBufferView(body) || isAnyArrayBuffer(body)) { | ||
| 58 | + return; | ||
| 59 | + } | ||
| 60 | + throw new ERR_INVALID_RETURN_PROPERTY_VALUE( | ||
| 61 | + `${allowString ? 'string, ' : ''}array buffer, or typed array`, | ||
| 62 | + hookName, | ||
| 63 | + 'source', | ||
| 64 | + body | ||
| 65 | + ); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + function stringify(body) { | ||
| 69 | + if (typeof body === 'string') return body; | ||
| 70 | + assertBufferSource(body, false, 'transformSource'); | ||
| 71 | + DECODER = DECODER === null ? new TextDecoder() : DECODER; | ||
| 72 | + return DECODER.decode(body); | ||
| 73 | + } | ||
| 74 | + | ||
| 42 | 75 | function errPath(url) { | |
| 43 | 76 | const parsed = new URL(url); | |
| 44 | 77 | if (parsed.protocol === 'file:') { | |
@@ -80,9 +113,10 @@ function initializeImportMeta(meta, { url }) { | |||
| 80 | 113 | translators.set('module', async function moduleStrategy(url) { | |
| 81 | 114 | let { source } = await this._getSource( | |
| 82 | 115 | url, { format: 'module' }, defaultGetSource); | |
| 83 | - source = `${source}`; | ||
| 116 | + assertBufferSource(source, true, 'getSource'); | ||
| 84 | 117 | ({ source } = await this._transformSource( | |
| 85 | 118 | source, { url, format: 'module' }, defaultTransformSource)); | |
| 119 | + source = stringify(source); | ||
| 86 | 120 | maybeCacheSourceMap(url, source); | |
| 87 | 121 | debug(`Translating StandardModule ${url}`); | |
| 88 | 122 | const module = new ModuleWrap(url, undefined, source, 0, 0); | |
@@ -157,9 +191,10 @@ translators.set('json', async function jsonStrategy(url) { | |||
| 157 | 191 | } | |
| 158 | 192 | let { source } = await this._getSource( | |
| 159 | 193 | url, { format: 'json' }, defaultGetSource); | |
| 160 | - source = `${source}`; | ||
| 194 | + assertBufferSource(source, true, 'getSource'); | ||
| 161 | 195 | ({ source } = await this._transformSource( | |
| 162 | 196 | source, { url, format: 'json' }, defaultTransformSource)); | |
| 197 | + source = stringify(source); | ||
| 163 | 198 | if (pathname) { | |
| 164 | 199 | // A require call could have been called on the same file during loading and | |
| 165 | 200 | // that resolves synchronously. To make sure we always return the identical | |
@@ -200,8 +235,10 @@ translators.set('wasm', async function(url) { | |||
| 200 | 235 | emitExperimentalWarning('Importing Web Assembly modules'); | |
| 201 | 236 | let { source } = await this._getSource( | |
| 202 | 237 | url, { format: 'wasm' }, defaultGetSource); | |
| 238 | + assertBufferSource(source, false, 'getSource'); | ||
| 203 | 239 | ({ source } = await this._transformSource( | |
| 204 | 240 | source, { url, format: 'wasm' }, defaultTransformSource)); | |
| 241 | + assertBufferSource(source, false, 'transformSource'); | ||
| 205 | 242 | debug(`Translating WASMModule ${url}`); | |
| 206 | 243 | let compiled; | |
| 207 | 244 | try { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,50 @@ | |||
| 1 | + // Flags: --experimental-loader ./test/fixtures/es-module-loaders/string-sources.mjs | ||
| 2 | + import { mustCall, mustNotCall } from '../common/index.mjs'; | ||
| 3 | + import assert from 'assert'; | ||
| 4 | + | ||
| 5 | + import('test:Array').then( | ||
| 6 | + mustNotCall('Should not accept Arrays'), | ||
| 7 | + mustCall((e) => { | ||
| 8 | + assert.strictEqual(e.code, 'ERR_INVALID_RETURN_PROPERTY_VALUE'); | ||
| 9 | + }) | ||
| 10 | + ); | ||
| 11 | + import('test:ArrayBuffer').then( | ||
| 12 | + mustCall(), | ||
| 13 | + mustNotCall('Should accept ArrayBuffers'), | ||
| 14 | + ); | ||
| 15 | + import('test:null').then( | ||
| 16 | + mustNotCall('Should not accept null'), | ||
| 17 | + mustCall((e) => { | ||
| 18 | + assert.strictEqual(e.code, 'ERR_INVALID_RETURN_PROPERTY_VALUE'); | ||
| 19 | + }) | ||
| 20 | + ); | ||
| 21 | + import('test:Object').then( | ||
| 22 | + mustNotCall('Should not stringify or valueOf Objects'), | ||
| 23 | + mustCall((e) => { | ||
| 24 | + assert.strictEqual(e.code, 'ERR_INVALID_RETURN_PROPERTY_VALUE'); | ||
| 25 | + }) | ||
| 26 | + ); | ||
| 27 | + import('test:SharedArrayBuffer').then( | ||
| 28 | + mustCall(), | ||
| 29 | + mustNotCall('Should accept SharedArrayBuffers'), | ||
| 30 | + ); | ||
| 31 | + import('test:string').then( | ||
| 32 | + mustCall(), | ||
| 33 | + mustNotCall('Should accept strings'), | ||
| 34 | + ); | ||
| 35 | + import('test:String').then( | ||
| 36 | + mustNotCall('Should not accept wrapper Strings'), | ||
| 37 | + mustCall((e) => { | ||
| 38 | + assert.strictEqual(e.code, 'ERR_INVALID_RETURN_PROPERTY_VALUE'); | ||
| 39 | + }) | ||
| 40 | + ); | ||
| 41 | + import('test:Uint8Array').then( | ||
| 42 | + mustCall(), | ||
| 43 | + mustNotCall('Should accept Uint8Arrays'), | ||
| 44 | + ); | ||
| 45 | + import('test:undefined').then( | ||
| 46 | + mustNotCall('Should not accept undefined'), | ||
| 47 | + mustCall((e) => { | ||
| 48 | + assert.strictEqual(e.code, 'ERR_INVALID_RETURN_PROPERTY_VALUE'); | ||
| 49 | + }) | ||
| 50 | + ); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,30 @@ | |||
| 1 | + const SOURCES = { | ||
| 2 | + __proto__: null, | ||
| 3 | + 'test:Array': ['1', '2'], // both `1,2` and `12` are valid ESM | ||
| 4 | + 'test:ArrayBuffer': new ArrayBuffer(0), | ||
| 5 | + 'test:null': null, | ||
| 6 | + 'test:Object': {}, | ||
| 7 | + 'test:SharedArrayBuffer': new SharedArrayBuffer(0), | ||
| 8 | + 'test:string': '', | ||
| 9 | + 'test:String': new String(''), | ||
| 10 | + 'test:Uint8Array': new Uint8Array(0), | ||
| 11 | + 'test:undefined': undefined, | ||
| 12 | + } | ||
| 13 | + export function resolve(specifier, context, defaultFn) { | ||
| 14 | + if (specifier.startsWith('test:')) { | ||
| 15 | + return { url: specifier }; | ||
| 16 | + } | ||
| 17 | + return defaultFn(specifier, context); | ||
| 18 | + } | ||
| 19 | + export function getFormat(href, context, defaultFn) { | ||
| 20 | + if (href.startsWith('test:')) { | ||
| 21 | + return { format: 'module' }; | ||
| 22 | + } | ||
| 23 | + return defaultFn(href, context); | ||
| 24 | + } | ||
| 25 | + export function getSource(href, context, defaultFn) { | ||
| 26 | + if (href.startsWith('test:')) { | ||
| 27 | + return { source: SOURCES[href] }; | ||
| 28 | + } | ||
| 29 | + return defaultFn(href, context); | ||
| 30 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,9 @@ | |||
| 1 | 1 | export async function transformSource( | |
| 2 | 2 | source, { url, format }, defaultTransformSource) { | |
| 3 | - if (source && source.replace) { | ||
| 3 | + if (format === 'module') { | ||
| 4 | + if (typeof source !== 'string') { | ||
| 5 | + source = new TextDecoder().decode(source); | ||
| 6 | + } | ||
| 4 | 7 | return { | |
| 5 | 8 | source: source.replace(`'A message';`, `'A message'.toUpperCase();`) | |
| 6 | 9 | }; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments