Skip to content

Commit 08ffbd1

Browse files
aduh95nodejs-github-bot
authored andcommittedOct 9, 2021
vm: add support for import assertions in dynamic imports
PR-URL: nodejs#40249 Reviewed-By: Bradley Farias <[email protected]> Reviewed-By: Guy Bedford <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Geoffrey Booth <[email protected]>
1 parent 879ff77 commit 08ffbd1

File tree

5 files changed

+90
-12
lines changed

5 files changed

+90
-12
lines changed
 

‎doc/api/vm.md

+46
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ executed in specific contexts.
5454
<!-- YAML
5555
added: v0.3.1
5656
changes:
57+
- version: REPLACEME
58+
pr-url: https://github.com/nodejs/node/pull/40249
59+
description: Added support for import assertions to the
60+
`importModuleDynamically` parameter.
5761
- version: v10.6.0
5862
pr-url: https://github.com/nodejs/node/pull/20300
5963
description: The `produceCachedData` is deprecated in favour of
@@ -91,6 +95,9 @@ changes:
9195
using it in a production environment.
9296
* `specifier` {string} specifier passed to `import()`
9397
* `script` {vm.Script}
98+
* `importAssertions` {Object} The `"assert"` value passed to the
99+
[`optionsExpression`][] optional parameter, or an empty object if no value
100+
was provided.
94101
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
95102
recommended in order to take advantage of error tracking, and to avoid
96103
issues with namespaces that contain `then` function exports.
@@ -642,6 +649,13 @@ The `vm.SourceTextModule` class provides the [Source Text Module Record][] as
642649
defined in the ECMAScript specification.
643650

644651
### `new vm.SourceTextModule(code[, options])`
652+
<!-- YAML
653+
changes:
654+
- version: REPLACEME
655+
pr-url: https://github.com/nodejs/node/pull/40249
656+
description: Added support for import assertions to the
657+
`importModuleDynamically` parameter.
658+
-->
645659

646660
* `code` {string} JavaScript Module code to parse
647661
* `options`
@@ -667,6 +681,9 @@ defined in the ECMAScript specification.
667681
`import()` will reject with [`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING`][].
668682
* `specifier` {string} specifier passed to `import()`
669683
* `module` {vm.Module}
684+
* `importAssertions` {Object} The `"assert"` value passed to the
685+
[`optionsExpression`][] optional parameter, or an empty object if no value
686+
was provided.
670687
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
671688
recommended in order to take advantage of error tracking, and to avoid
672689
issues with namespaces that contain `then` function exports.
@@ -852,6 +869,10 @@ const vm = require('vm');
852869
<!-- YAML
853870
added: v10.10.0
854871
changes:
872+
- version: REPLACEME
873+
pr-url: https://github.com/nodejs/node/pull/40249
874+
description: Added support for import assertions to the
875+
`importModuleDynamically` parameter.
855876
- version: v15.9.0
856877
pr-url: https://github.com/nodejs/node/pull/35431
857878
description: Added `importModuleDynamically` option again.
@@ -893,6 +914,9 @@ changes:
893914
considered stable.
894915
* `specifier` {string} specifier passed to `import()`
895916
* `function` {Function}
917+
* `importAssertions` {Object} The `"assert"` value passed to the
918+
[`optionsExpression`][] optional parameter, or an empty object if no value
919+
was provided.
896920
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
897921
recommended in order to take advantage of error tracking, and to avoid
898922
issues with namespaces that contain `then` function exports.
@@ -1068,6 +1092,10 @@ vm.measureMemory({ mode: 'detailed', execution: 'eager' })
10681092
<!-- YAML
10691093
added: v0.3.1
10701094
changes:
1095+
- version: REPLACEME
1096+
pr-url: https://github.com/nodejs/node/pull/40249
1097+
description: Added support for import assertions to the
1098+
`importModuleDynamically` parameter.
10711099
- version: v6.3.0
10721100
pr-url: https://github.com/nodejs/node/pull/6635
10731101
description: The `breakOnSigint` option is supported now.
@@ -1113,6 +1141,9 @@ changes:
11131141
using it in a production environment.
11141142
* `specifier` {string} specifier passed to `import()`
11151143
* `script` {vm.Script}
1144+
* `importAssertions` {Object} The `"assert"` value passed to the
1145+
[`optionsExpression`][] optional parameter, or an empty object if no value
1146+
was provided.
11161147
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
11171148
recommended in order to take advantage of error tracking, and to avoid
11181149
issues with namespaces that contain `then` function exports.
@@ -1145,6 +1176,10 @@ console.log(contextObject);
11451176
<!-- YAML
11461177
added: v0.3.1
11471178
changes:
1179+
- version: REPLACEME
1180+
pr-url: https://github.com/nodejs/node/pull/40249
1181+
description: Added support for import assertions to the
1182+
`importModuleDynamically` parameter.
11481183
- version: v14.6.0
11491184
pr-url: https://github.com/nodejs/node/pull/34023
11501185
description: The `microtaskMode` option is supported now.
@@ -1211,6 +1246,9 @@ changes:
12111246
using it in a production environment.
12121247
* `specifier` {string} specifier passed to `import()`
12131248
* `script` {vm.Script}
1249+
* `importAssertions` {Object} The `"assert"` value passed to the
1250+
[`optionsExpression`][] optional parameter, or an empty object if no value
1251+
was provided.
12141252
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
12151253
recommended in order to take advantage of error tracking, and to avoid
12161254
issues with namespaces that contain `then` function exports.
@@ -1247,6 +1285,10 @@ console.log(contextObject);
12471285
<!-- YAML
12481286
added: v0.3.1
12491287
changes:
1288+
- version: REPLACEME
1289+
pr-url: https://github.com/nodejs/node/pull/40249
1290+
description: Added support for import assertions to the
1291+
`importModuleDynamically` parameter.
12501292
- version: v6.3.0
12511293
pr-url: https://github.com/nodejs/node/pull/6635
12521294
description: The `breakOnSigint` option is supported now.
@@ -1290,6 +1332,9 @@ changes:
12901332
using it in a production environment.
12911333
* `specifier` {string} specifier passed to `import()`
12921334
* `script` {vm.Script}
1335+
* `importAssertions` {Object} The `"assert"` value passed to the
1336+
[`optionsExpression`][] optional parameter, or an empty object if no value
1337+
was provided.
12931338
* Returns: {Module Namespace Object|vm.Module} Returning a `vm.Module` is
12941339
recommended in order to take advantage of error tracking, and to avoid
12951340
issues with namespaces that contain `then` function exports.
@@ -1452,6 +1497,7 @@ are not controllable through the timeout either.
14521497
[`Error`]: errors.md#class-error
14531498
[`URL`]: url.md#class-url
14541499
[`eval()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
1500+
[`optionsExpression`]: https://tc39.es/proposal-import-assertions/#sec-evaluate-import-call
14551501
[`script.runInContext()`]: #scriptrunincontextcontextifiedobject-options
14561502
[`script.runInThisContext()`]: #scriptruninthiscontextoptions
14571503
[`url.origin`]: url.md#urlorigin

‎lib/internal/process/esm_loader.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
'use strict';
22

3+
const {
4+
ObjectCreate,
5+
} = primordials;
6+
37
const {
48
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING,
59
} = require('internal/errors').codes;
@@ -22,13 +26,14 @@ exports.initializeImportMetaObject = function(wrap, meta) {
2226
}
2327
};
2428

25-
exports.importModuleDynamicallyCallback = async function(wrap, specifier) {
29+
exports.importModuleDynamicallyCallback =
30+
async function importModuleDynamicallyCallback(wrap, specifier, assertions) {
2631
const { callbackMap } = internalBinding('module_wrap');
2732
if (callbackMap.has(wrap)) {
2833
const { importModuleDynamically } = callbackMap.get(wrap);
2934
if (importModuleDynamically !== undefined) {
3035
return importModuleDynamically(
31-
specifier, getModuleFromWrap(wrap) || wrap);
36+
specifier, getModuleFromWrap(wrap) || wrap, assertions);
3237
}
3338
}
3439
throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING();
@@ -69,6 +74,7 @@ async function initializeLoader() {
6974
const exports = await internalEsmLoader.import(
7075
customLoaders,
7176
pathToFileURL(cwd).href,
77+
ObjectCreate(null),
7278
);
7379

7480
// Hooks must then be added to external/public loader

‎lib/vm.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ function compileFunction(code, params, options = {}) {
378378
const wrapped = importModuleDynamicallyWrap(importModuleDynamically);
379379
const func = result.function;
380380
callbackMap.set(result.cacheKey, {
381-
importModuleDynamically: (s, _k) => wrapped(s, func),
381+
importModuleDynamically: (s, _k, i) => wrapped(s, func, i),
382382
});
383383
}
384384

‎src/module_wrap.cc

+20-8
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,21 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
253253
args.GetReturnValue().Set(that);
254254
}
255255

256+
static Local<Object> createImportAssertionContainer(Environment* env,
257+
Isolate* isolate, Local<FixedArray> raw_assertions) {
258+
Local<Object> assertions =
259+
Object::New(isolate, v8::Null(env->isolate()), nullptr, nullptr, 0);
260+
for (int i = 0; i < raw_assertions->Length(); i += 3) {
261+
assertions
262+
->Set(env->context(),
263+
raw_assertions->Get(env->context(), i).As<String>(),
264+
raw_assertions->Get(env->context(), i + 1).As<Value>())
265+
.ToChecked();
266+
}
267+
268+
return assertions;
269+
}
270+
256271
void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
257272
Environment* env = Environment::GetCurrent(args);
258273
Isolate* isolate = args.GetIsolate();
@@ -288,14 +303,7 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) {
288303

289304
Local<FixedArray> raw_assertions = module_request->GetImportAssertions();
290305
Local<Object> assertions =
291-
Object::New(isolate, v8::Null(env->isolate()), nullptr, nullptr, 0);
292-
for (int i = 0; i < raw_assertions->Length(); i += 3) {
293-
assertions
294-
->Set(env->context(),
295-
raw_assertions->Get(env->context(), i).As<String>(),
296-
raw_assertions->Get(env->context(), i + 1).As<Value>())
297-
.ToChecked();
298-
}
306+
createImportAssertionContainer(env, isolate, raw_assertions);
299307

300308
Local<Value> argv[] = {
301309
specifier,
@@ -602,9 +610,13 @@ static MaybeLocal<Promise> ImportModuleDynamically(
602610
UNREACHABLE();
603611
}
604612

613+
Local<Object> assertions =
614+
createImportAssertionContainer(env, isolate, import_assertions);
615+
605616
Local<Value> import_args[] = {
606617
object,
607618
Local<Value>(specifier),
619+
assertions,
608620
};
609621

610622
Local<Value> result;

‎test/parallel/test-vm-module-dynamic-import.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
// Flags: --experimental-vm-modules
3+
// Flags: --experimental-vm-modules --harmony-import-assertions
44

55
const common = require('../common');
66

@@ -56,6 +56,20 @@ async function test() {
5656
assert.strictEqual(foo.namespace, await globalThis.fooResult);
5757
delete globalThis.fooResult;
5858
}
59+
60+
{
61+
const s = new Script('import("foo", { assert: { key: "value" } })', {
62+
importModuleDynamically: common.mustCall((specifier, wrap, assertion) => {
63+
assert.strictEqual(specifier, 'foo');
64+
assert.strictEqual(wrap, s);
65+
assert.deepStrictEqual(assertion, { __proto__: null, key: 'value' });
66+
return foo;
67+
}),
68+
});
69+
70+
const result = s.runInThisContext();
71+
assert.strictEqual(foo.namespace, await result);
72+
}
5973
}
6074

6175
async function testInvalid() {

0 commit comments

Comments
 (0)
Please sign in to comment.