Skip to content

Commit a193be3

Browse files
aduh95richardlau
authored andcommitted
esm: use import attributes instead of import assertions
The old import assertions proposal has been renamed to "import attributes" with the follwing major changes: 1. The keyword is now `with` instead of `assert`. 2. Unknown assertions cause an error rather than being ignored, This commit updates the documentation to encourage folks to use the new syntax, and add aliases for module customization hooks. PR-URL: #50140 Backport-PR-URL: #51136 Fixes: #50134 Refs: v8/v8@159c82c Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Jacob Smith <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
1 parent c13969e commit a193be3

18 files changed

+68
-62
lines changed

.eslintrc.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,7 @@ module.exports = {
4444
parserOptions: {
4545
babelOptions: {
4646
plugins: [
47-
[
48-
Module._findPath('@babel/plugin-syntax-import-attributes'),
49-
{ deprecatedAssertSyntax: true },
50-
],
47+
Module._findPath('@babel/plugin-syntax-import-attributes'),
5148
],
5249
},
5350
requireConfigFile: false,

doc/api/esm.md

+11-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
<!-- YAML
88
added: v8.5.0
99
changes:
10+
- version: REPLACEME
11+
pr-url: https://github.com/nodejs/node/pull/50140
12+
description: Add experimental support for import attributes.
1013
- version: v18.19.0
1114
pr-url: https://github.com/nodejs/node/pull/44710
1215
description: Module customization hooks are executed off the main thread.
@@ -202,7 +205,7 @@ added: v12.10.0
202205

203206
```js
204207
import 'data:text/javascript,console.log("hello!");';
205-
import _ from 'data:application/json,"world!"' assert { type: 'json' };
208+
import _ from 'data:application/json,"world!"' with { type: 'json' };
206209
```
207210

208211
`data:` URLs only resolve [bare specifiers][Terminology] for builtin modules
@@ -243,26 +246,25 @@ added:
243246
- v17.1.0
244247
- v16.14.0
245248
changes:
246-
- version: v18.19.0
249+
- version: REPLACEME
247250
pr-url: https://github.com/nodejs/node/pull/50140
248251
description: Switch from Import Assertions to Import Attributes.
249252
-->
250253

251254
> Stability: 1.1 - Active development
252255
253256
> This feature was previously named "Import assertions", and using the `assert`
254-
> keyword instead of `with`. Because the version of V8 on this release line does
255-
> not support the `with` keyword, you need to keep using `assert` to support
256-
> this version of Node.js.
257+
> keyword instead of `with`. Any uses in code of the prior `assert` keyword
258+
> should be updated to use `with` instead.
257259
258260
The [Import Attributes proposal][] adds an inline syntax for module import
259261
statements to pass on more information alongside the module specifier.
260262

261263
```js
262-
import fooData from './foo.json' assert { type: 'json' };
264+
import fooData from './foo.json' with { type: 'json' };
263265

264266
const { default: barData } =
265-
await import('./bar.json', { assert: { type: 'json' } });
267+
await import('./bar.json', { with: { type: 'json' } });
266268
```
267269

268270
Node.js supports the following `type` values, for which the attribute is
@@ -555,10 +557,10 @@ separate cache.
555557
JSON files can be referenced by `import`:
556558

557559
```js
558-
import packageConfig from './package.json' assert { type: 'json' };
560+
import packageConfig from './package.json' with { type: 'json' };
559561
```
560562
561-
The `assert { type: 'json' }` syntax is mandatory; see [Import Attributes][].
563+
The `with { type: 'json' }` syntax is mandatory; see [Import Attributes][].
562564
563565
The imported JSON only exposes a `default` export. There is no support for named
564566
exports. A cache entry is created in the CommonJS cache to avoid duplication.

src/node.cc

+7
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,13 @@ int ProcessGlobalArgs(std::vector<std::string>* args,
745745
"--no-harmony-import-assertions") == v8_args.end()) {
746746
v8_args.emplace_back("--harmony-import-assertions");
747747
}
748+
// TODO(aduh95): remove this when the harmony-import-attributes flag
749+
// is removed in V8.
750+
if (std::find(v8_args.begin(),
751+
v8_args.end(),
752+
"--no-harmony-import-attributes") == v8_args.end()) {
753+
v8_args.emplace_back("--harmony-import-attributes");
754+
}
748755

749756
auto env_opts = per_process::cli_options->per_isolate->per_env;
750757
if (std::find(v8_args.begin(), v8_args.end(),

test/es-module/test-esm-assertionless-json-import.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ async function test() {
99
import('../fixtures/experimental.json'),
1010
import(
1111
'../fixtures/experimental.json',
12-
{ assert: { type: 'json' } }
12+
{ with: { type: 'json' } }
1313
),
1414
]);
1515

@@ -24,7 +24,7 @@ async function test() {
2424
import('../fixtures/experimental.json?test'),
2525
import(
2626
'../fixtures/experimental.json?test',
27-
{ assert: { type: 'json' } }
27+
{ with: { type: 'json' } }
2828
),
2929
]);
3030

@@ -39,7 +39,7 @@ async function test() {
3939
import('../fixtures/experimental.json#test'),
4040
import(
4141
'../fixtures/experimental.json#test',
42-
{ assert: { type: 'json' } }
42+
{ with: { type: 'json' } }
4343
),
4444
]);
4545

@@ -54,7 +54,7 @@ async function test() {
5454
import('../fixtures/experimental.json?test2#test'),
5555
import(
5656
'../fixtures/experimental.json?test2#test',
57-
{ assert: { type: 'json' } }
57+
{ with: { type: 'json' } }
5858
),
5959
]);
6060

@@ -69,7 +69,7 @@ async function test() {
6969
import('data:application/json,{"ofLife":42}'),
7070
import(
7171
'data:application/json,{"ofLife":42}',
72-
{ assert: { type: 'json' } }
72+
{ with: { type: 'json' } }
7373
),
7474
]);
7575

test/es-module/test-esm-data-urls.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -60,36 +60,36 @@ function createBase64URL(mime, body) {
6060
}
6161
{
6262
const ns = await import('data:application/json;foo="test,"this"',
63-
{ assert: { type: 'json' } });
63+
{ with: { type: 'json' } });
6464
assert.deepStrictEqual(Object.keys(ns), ['default']);
6565
assert.strictEqual(ns.default, 'this');
6666
}
6767
{
6868
const ns = await import(`data:application/json;foo=${
6969
encodeURIComponent('test,')
70-
},0`, { assert: { type: 'json' } });
70+
},0`, { with: { type: 'json' } });
7171
assert.deepStrictEqual(Object.keys(ns), ['default']);
7272
assert.strictEqual(ns.default, 0);
7373
}
7474
{
7575
await assert.rejects(async () =>
7676
import('data:application/json;foo="test,",0',
77-
{ assert: { type: 'json' } }), {
77+
{ with: { type: 'json' } }), {
7878
name: 'SyntaxError',
7979
message: /Unexpected end of JSON input/
8080
});
8181
}
8282
{
8383
const body = '{"x": 1}';
8484
const plainESMURL = createURL('application/json', body);
85-
const ns = await import(plainESMURL, { assert: { type: 'json' } });
85+
const ns = await import(plainESMURL, { with: { type: 'json' } });
8686
assert.deepStrictEqual(Object.keys(ns), ['default']);
8787
assert.strictEqual(ns.default.x, 1);
8888
}
8989
{
9090
const body = '{"default": 2}';
9191
const plainESMURL = createURL('application/json', body);
92-
const ns = await import(plainESMURL, { assert: { type: 'json' } });
92+
const ns = await import(plainESMURL, { with: { type: 'json' } });
9393
assert.deepStrictEqual(Object.keys(ns), ['default']);
9494
assert.strictEqual(ns.default.default, 2);
9595
}

test/es-module/test-esm-dynamic-import-attribute.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const { strictEqual } = require('assert');
55
async function test() {
66
{
77
const results = await Promise.allSettled([
8-
import('../fixtures/empty.js', { assert: { type: 'json' } }),
8+
import('../fixtures/empty.js', { with: { type: 'json' } }),
99
import('../fixtures/empty.js'),
1010
]);
1111

@@ -16,7 +16,7 @@ async function test() {
1616
{
1717
const results = await Promise.allSettled([
1818
import('../fixtures/empty.js'),
19-
import('../fixtures/empty.js', { assert: { type: 'json' } }),
19+
import('../fixtures/empty.js', { with: { type: 'json' } }),
2020
]);
2121

2222
strictEqual(results[0].status, 'fulfilled');
@@ -25,7 +25,7 @@ async function test() {
2525

2626
{
2727
const results = await Promise.allSettled([
28-
import('../fixtures/empty.json', { assert: { type: 'json' } }),
28+
import('../fixtures/empty.json', { with: { type: 'json' } }),
2929
import('../fixtures/empty.json'),
3030
]);
3131

@@ -36,7 +36,7 @@ async function test() {
3636
{
3737
const results = await Promise.allSettled([
3838
import('../fixtures/empty.json'),
39-
import('../fixtures/empty.json', { assert: { type: 'json' } }),
39+
import('../fixtures/empty.json', { with: { type: 'json' } }),
4040
]);
4141

4242
strictEqual(results[0].status, 'rejected');

test/es-module/test-esm-dynamic-import-attribute.mjs

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { strictEqual } from 'assert';
33

44
{
55
const results = await Promise.allSettled([
6-
import('../fixtures/empty.js', { assert: { type: 'json' } }),
6+
import('../fixtures/empty.js', { with: { type: 'json' } }),
77
import('../fixtures/empty.js'),
88
]);
99

@@ -14,7 +14,7 @@ import { strictEqual } from 'assert';
1414
{
1515
const results = await Promise.allSettled([
1616
import('../fixtures/empty.js'),
17-
import('../fixtures/empty.js', { assert: { type: 'json' } }),
17+
import('../fixtures/empty.js', { with: { type: 'json' } }),
1818
]);
1919

2020
strictEqual(results[0].status, 'fulfilled');
@@ -23,7 +23,7 @@ import { strictEqual } from 'assert';
2323

2424
{
2525
const results = await Promise.allSettled([
26-
import('../fixtures/empty.json', { assert: { type: 'json' } }),
26+
import('../fixtures/empty.json', { with: { type: 'json' } }),
2727
import('../fixtures/empty.json'),
2828
]);
2929

@@ -34,7 +34,7 @@ import { strictEqual } from 'assert';
3434
{
3535
const results = await Promise.allSettled([
3636
import('../fixtures/empty.json'),
37-
import('../fixtures/empty.json', { assert: { type: 'json' } }),
37+
import('../fixtures/empty.json', { with: { type: 'json' } }),
3838
]);
3939

4040
strictEqual(results[0].status, 'rejected');
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import '../common/index.mjs';
22
import { strictEqual } from 'assert';
33

4-
import secret from '../fixtures/experimental.json' assert { type: 'json' };
4+
import secret from '../fixtures/experimental.json' with { type: 'json' };
55

66
strictEqual(secret.ofLife, 42);

test/es-module/test-esm-import-attributes-2.mjs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import '../common/index.mjs';
22
import { strictEqual } from 'assert';
33

4-
import secret0 from '../fixtures/experimental.json' assert { type: 'json' };
4+
import secret0 from '../fixtures/experimental.json' with { type: 'json' };
55
const secret1 = await import('../fixtures/experimental.json', {
6-
assert: { type: 'json' },
6+
with: { type: 'json' },
77
});
88

99
strictEqual(secret0.ofLife, 42);

test/es-module/test-esm-import-attributes-3.mjs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import '../common/index.mjs';
22
import { strictEqual } from 'assert';
33

4-
import secret0 from '../fixtures/experimental.json' assert { type: 'json' };
4+
import secret0 from '../fixtures/experimental.json' with { type: 'json' };
55
const secret1 = await import('../fixtures/experimental.json',
6-
{ assert: { type: 'json' } });
6+
{ with: { type: 'json' } });
77

88
strictEqual(secret0.ofLife, 42);
99
strictEqual(secret1.default.ofLife, 42);

test/es-module/test-esm-import-attributes-errors.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,27 @@ const jsonModuleDataUrl = 'data:application/json,""';
77

88
async function test() {
99
await rejects(
10-
import('data:text/css,', { assert: { type: 'css' } }),
10+
import('data:text/css,', { with: { type: 'css' } }),
1111
{ code: 'ERR_UNKNOWN_MODULE_FORMAT' }
1212
);
1313

1414
await rejects(
15-
import('data:text/css,', { assert: { unsupportedAttribute: 'value' } }),
15+
import('data:text/css,', { with: { unsupportedAttribute: 'value' } }),
1616
{ code: 'ERR_IMPORT_ATTRIBUTE_UNSUPPORTED' }
1717
);
1818

1919
await rejects(
20-
import(`data:text/javascript,import${JSON.stringify(jsModuleDataUrl)}assert{type:"json"}`),
20+
import(`data:text/javascript,import${JSON.stringify(jsModuleDataUrl)}with{type:"json"}`),
2121
{ code: 'ERR_IMPORT_ASSERTION_TYPE_FAILED' }
2222
);
2323

2424
await rejects(
25-
import(jsModuleDataUrl, { assert: { type: 'json' } }),
25+
import(jsModuleDataUrl, { with: { type: 'json' } }),
2626
{ code: 'ERR_IMPORT_ASSERTION_TYPE_FAILED' }
2727
);
2828

2929
await rejects(
30-
import(jsModuleDataUrl, { assert: { type: 'unsupported' } }),
30+
import(jsModuleDataUrl, { with: { type: 'unsupported' } }),
3131
{ code: 'ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED' }
3232
);
3333

@@ -37,17 +37,17 @@ async function test() {
3737
);
3838

3939
await rejects(
40-
import(jsonModuleDataUrl, { assert: {} }),
40+
import(jsonModuleDataUrl, { with: {} }),
4141
{ code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING' }
4242
);
4343

4444
await rejects(
45-
import(jsonModuleDataUrl, { assert: { foo: 'bar' } }),
45+
import(jsonModuleDataUrl, { with: { foo: 'bar' } }),
4646
{ code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING' }
4747
);
4848

4949
await rejects(
50-
import(jsonModuleDataUrl, { assert: { type: 'unsupported' } }),
50+
import(jsonModuleDataUrl, { with: { type: 'unsupported' } }),
5151
{ code: 'ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED' }
5252
);
5353
}

test/es-module/test-esm-import-attributes-errors.mjs

+7-7
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,22 @@ const jsonModuleDataUrl = 'data:application/json,""';
77
await rejects(
88
// This rejects because of the unsupported MIME type, not because of the
99
// unsupported assertion.
10-
import('data:text/css,', { assert: { type: 'css' } }),
10+
import('data:text/css,', { with: { type: 'css' } }),
1111
{ code: 'ERR_UNKNOWN_MODULE_FORMAT' }
1212
);
1313

1414
await rejects(
15-
import(`data:text/javascript,import${JSON.stringify(jsModuleDataUrl)}assert{type:"json"}`),
15+
import(`data:text/javascript,import${JSON.stringify(jsModuleDataUrl)}with{type:"json"}`),
1616
{ code: 'ERR_IMPORT_ASSERTION_TYPE_FAILED' }
1717
);
1818

1919
await rejects(
20-
import(jsModuleDataUrl, { assert: { type: 'json' } }),
20+
import(jsModuleDataUrl, { with: { type: 'json' } }),
2121
{ code: 'ERR_IMPORT_ASSERTION_TYPE_FAILED' }
2222
);
2323

2424
await rejects(
25-
import(import.meta.url, { assert: { type: 'unsupported' } }),
25+
import(import.meta.url, { with: { type: 'unsupported' } }),
2626
{ code: 'ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED' }
2727
);
2828

@@ -32,16 +32,16 @@ await rejects(
3232
);
3333

3434
await rejects(
35-
import(jsonModuleDataUrl, { assert: {} }),
35+
import(jsonModuleDataUrl, { with: {} }),
3636
{ code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING' }
3737
);
3838

3939
await rejects(
40-
import(jsonModuleDataUrl, { assert: { foo: 'bar' } }),
40+
import(jsonModuleDataUrl, { with: { foo: 'bar' } }),
4141
{ code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING' }
4242
);
4343

4444
await rejects(
45-
import(jsonModuleDataUrl, { assert: { type: 'unsupported' } }),
45+
import(jsonModuleDataUrl, { with: { type: 'unsupported' } }),
4646
{ code: 'ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED' }
4747
);

test/es-module/test-esm-json-cache.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { createRequire } from 'module';
66

77
import mod from '../fixtures/es-modules/json-cache/mod.cjs';
88
import another from '../fixtures/es-modules/json-cache/another.cjs';
9-
import test from '../fixtures/es-modules/json-cache/test.json' assert
9+
import test from '../fixtures/es-modules/json-cache/test.json' with
1010
{ type: 'json' };
1111

1212
const require = createRequire(import.meta.url);

0 commit comments

Comments
 (0)