Skip to content

Commit 10ba639

Browse files
committed
Improve assertion validation and errors, add tests
1 parent bd7c391 commit 10ba639

8 files changed

+166
-67
lines changed

lib/internal/errors.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -1083,13 +1083,13 @@ E('ERR_HTTP_SOCKET_ENCODING',
10831083
E('ERR_HTTP_TRAILER_INVALID',
10841084
'Trailers are invalid with this transfer encoding', Error);
10851085
E('ERR_ILLEGAL_CONSTRUCTOR', 'Illegal constructor', TypeError);
1086-
E('ERR_IMPORT_ASSERTION_DISALLOWED',
1087-
'Import assertions are not allowed for modules of format "%s"',
1088-
SyntaxError);
1089-
E('ERR_IMPORT_ASSERTION_INVALID',
1090-
'Modules of format "%s" need an import assertion %s of "%s"', TypeError);
1091-
E('ERR_IMPORT_ASSERTION_MISSING',
1092-
'Modules of format "%s" need an import assertion %s of "%s"', SyntaxError);
1086+
E('ERR_IMPORT_ASSERTION_TYPE_FAILED',
1087+
'Modules of format "%s" need an import assertion type "%s"', TypeError);
1088+
E('ERR_IMPORT_ASSERTION_TYPE_MISSING',
1089+
'Modules of format "%s" need an import assertion type "%s"', SyntaxError);
1090+
E('ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED',
1091+
'Modules of format "%s" do not support import assertion type "%s"',
1092+
TypeError);
10931093
E('ERR_INCOMPATIBLE_OPTION_PAIR',
10941094
'Option "%s" cannot be used in combination with option "%s"', TypeError);
10951095
E('ERR_INPUT_TYPE_NOT_ALLOWED', '--input-type can only be used with string ' +

lib/internal/modules/esm/assert.js

+17-14
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@ const {
66
} = primordials;
77

88
const {
9-
ERR_IMPORT_ASSERTION_DISALLOWED,
10-
ERR_IMPORT_ASSERTION_INVALID,
11-
ERR_IMPORT_ASSERTION_MISSING,
12-
ERR_UNKNOWN_MODULE_FORMAT,
9+
ERR_IMPORT_ASSERTION_TYPE_FAILED,
10+
ERR_IMPORT_ASSERTION_TYPE_MISSING,
11+
ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED,
1312
} = require('internal/errors').codes;
1413

14+
/**
15+
* Define a map of module formats to import assertion types (the value of `type` in `assert { type: 'json' }`).
16+
* A value of `false` means that the presence of an import assertion type for this format should throw an error.
17+
* This matches browser behavior, where `import('data:text/javascript,export{}', { assert: { type: 'javascript' } })` throws.
18+
* @type {Map<string, string | false}
19+
*/
1520
const formatTypeMap = new SafeMap([
1621
['builtin', false],
1722
['commonjs', false],
@@ -22,26 +27,24 @@ const formatTypeMap = new SafeMap([
2227

2328

2429
function validateAssertions(format, importAssertions) {
25-
let validType;
26-
try {
27-
validType = formatTypeMap.get(format);
28-
} catch {
29-
throw new ERR_UNKNOWN_MODULE_FORMAT(format);
30-
}
30+
const validType = formatTypeMap.get(format);
3131

32-
if (validType === false) {
32+
if (validType === undefined) {
33+
// Ignore assertions for module types we don’t recognize, to allow new formats in the future
34+
return true;
35+
} else if (validType === false) {
3336
if (!importAssertions ||
3437
!ObjectPrototypeHasOwnProperty(importAssertions, 'type')) {
3538
return true;
3639
}
37-
throw new ERR_IMPORT_ASSERTION_DISALLOWED(format);
40+
throw new ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED(format, validType);
3841
} else {
3942
if (validType === importAssertions?.type) {
4043
return true;
4144
} else if (!ObjectPrototypeHasOwnProperty(importAssertions, 'type')) {
42-
throw new ERR_IMPORT_ASSERTION_MISSING(format, 'type', validType);
45+
throw new ERR_IMPORT_ASSERTION_TYPE_MISSING(format, validType);
4346
} else {
44-
throw new ERR_IMPORT_ASSERTION_INVALID(format, 'type', validType);
47+
throw new ERR_IMPORT_ASSERTION_TYPE_FAILED(format, validType);
4548
}
4649
}
4750
}
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,9 @@
11
// Flags: --experimental-json-modules
22
'use strict';
33
const common = require('../common');
4-
const { rejects, strictEqual } = require('assert');
5-
6-
const jsModuleDataUrl = 'data:text/javascript,export{}';
4+
const { strictEqual } = require('assert');
75

86
async function test() {
9-
await rejects(
10-
import(`data:text/javascript,import${JSON.stringify(jsModuleDataUrl)}assert{type:"json"}`),
11-
{ code: 'ERR_IMPORT_ASSERTION_DISALLOWED' }
12-
);
13-
14-
await rejects(
15-
import(jsModuleDataUrl, { assert: { type: 'json' } }),
16-
{ code: 'ERR_IMPORT_ASSERTION_DISALLOWED' }
17-
);
18-
19-
await rejects(
20-
import('data:text/javascript,', { assert: { type: 'unsupported' } }),
21-
{ code: 'ERR_IMPORT_ASSERTION_DISALLOWED' }
22-
);
23-
24-
await rejects(
25-
import('data:text/javascript,', { assert: { type: 'undefined' } }),
26-
{ code: 'ERR_IMPORT_ASSERTION_DISALLOWED' }
27-
);
28-
297
{
308
const results = await Promise.allSettled([
319
import('../fixtures/empty.js', { assert: { type: 'json' } }),
@@ -45,6 +23,26 @@ async function test() {
4523
strictEqual(results[0].status, 'fulfilled');
4624
strictEqual(results[1].status, 'rejected');
4725
}
26+
27+
{
28+
const results = await Promise.allSettled([
29+
import('../fixtures/empty.json', { assert: { type: 'json' } }),
30+
import('../fixtures/empty.json'),
31+
]);
32+
33+
strictEqual(results[0].status, 'fulfilled');
34+
strictEqual(results[1].status, 'rejected');
35+
}
36+
37+
{
38+
const results = await Promise.allSettled([
39+
import('../fixtures/empty.json'),
40+
import('../fixtures/empty.json', { assert: { type: 'json' } }),
41+
]);
42+
43+
strictEqual(results[0].status, 'rejected');
44+
strictEqual(results[1].status, 'fulfilled');
45+
}
4846
}
4947

5048
test().then(common.mustCall());
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,6 @@
11
// Flags: --experimental-json-modules
22
import '../common/index.mjs';
3-
import { rejects, strictEqual } from 'assert';
4-
5-
const jsModuleDataUrl = 'data:text/javascript,export{}';
6-
7-
await rejects(
8-
import(`data:text/javascript,import${JSON.stringify(jsModuleDataUrl)}assert{type:"json"}`),
9-
{ code: 'ERR_IMPORT_ASSERTION_DISALLOWED' }
10-
);
11-
12-
await rejects(
13-
import(jsModuleDataUrl, { assert: { type: 'json' } }),
14-
{ code: 'ERR_IMPORT_ASSERTION_DISALLOWED' }
15-
);
16-
17-
await rejects(
18-
import(import.meta.url, { assert: { type: 'unsupported' } }),
19-
{ code: 'ERR_IMPORT_ASSERTION_DISALLOWED' }
20-
);
21-
22-
await rejects(
23-
import(import.meta.url, { assert: { type: 'undefined' } }),
24-
{ code: 'ERR_IMPORT_ASSERTION_DISALLOWED' }
25-
);
3+
import { strictEqual } from 'assert';
264

275
{
286
const results = await Promise.allSettled([
@@ -43,3 +21,23 @@ await rejects(
4321
strictEqual(results[0].status, 'fulfilled');
4422
strictEqual(results[1].status, 'rejected');
4523
}
24+
25+
{
26+
const results = await Promise.allSettled([
27+
import('../fixtures/empty.json', { assert: { type: 'json' } }),
28+
import('../fixtures/empty.json'),
29+
]);
30+
31+
strictEqual(results[0].status, 'fulfilled');
32+
strictEqual(results[1].status, 'rejected');
33+
}
34+
35+
{
36+
const results = await Promise.allSettled([
37+
import('../fixtures/empty.json'),
38+
import('../fixtures/empty.json', { assert: { type: 'json' } }),
39+
]);
40+
41+
strictEqual(results[0].status, 'rejected');
42+
strictEqual(results[1].status, 'fulfilled');
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Flags: --experimental-json-modules
2+
'use strict';
3+
const common = require('../common');
4+
const { rejects, strictEqual } = require('assert');
5+
6+
const jsModuleDataUrl = 'data:text/javascript,export{}';
7+
const jsonModuleDataUrl = 'data:application/json,""';
8+
9+
async function test() {
10+
await rejects(
11+
// This rejects because of the unsupported MIME type, not because of the unsupported assertion
12+
import(`data:text/css,`, { assert: { type: 'css' } }),
13+
{ code: 'ERR_INVALID_MODULE_SPECIFIER' }
14+
)
15+
16+
await rejects(
17+
import(`data:text/javascript,import${JSON.stringify(jsModuleDataUrl)}assert{type:"json"}`),
18+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED' }
19+
);
20+
21+
await rejects(
22+
import(jsModuleDataUrl, { assert: { type: 'json' } }),
23+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED' }
24+
);
25+
26+
await rejects(
27+
import('data:text/javascript,', { assert: { type: 'unsupported' } }),
28+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED' }
29+
);
30+
31+
await rejects(
32+
import(jsonModuleDataUrl),
33+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING' }
34+
);
35+
36+
await rejects(
37+
import(jsonModuleDataUrl, { assert: {} }),
38+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING' }
39+
);
40+
41+
await rejects(
42+
import(jsonModuleDataUrl, { assert: { foo: 'bar' } }),
43+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING' }
44+
);
45+
46+
await rejects(
47+
import(jsonModuleDataUrl, { assert: { type: 'unsupported' }}),
48+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_FAILED' }
49+
);
50+
}
51+
52+
test().then(common.mustCall());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Flags: --experimental-json-modules
2+
import '../common/index.mjs';
3+
import { rejects } from 'assert';
4+
5+
const jsModuleDataUrl = 'data:text/javascript,export{}';
6+
const jsonModuleDataUrl = 'data:application/json,""';
7+
8+
await rejects(
9+
// This rejects because of the unsupported MIME type, not because of the unsupported assertion
10+
import(`data:text/css,`, { assert: { type: 'css' } }),
11+
{ code: 'ERR_INVALID_MODULE_SPECIFIER' }
12+
)
13+
14+
await rejects(
15+
import(`data:text/javascript,import${JSON.stringify(jsModuleDataUrl)}assert{type:"json"}`),
16+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED' }
17+
);
18+
19+
await rejects(
20+
import(jsModuleDataUrl, { assert: { type: 'json' } }),
21+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED' }
22+
);
23+
24+
await rejects(
25+
import(import.meta.url, { assert: { type: 'unsupported' } }),
26+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED' }
27+
);
28+
29+
await rejects(
30+
import(jsonModuleDataUrl),
31+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING' }
32+
);
33+
34+
await rejects(
35+
import(jsonModuleDataUrl, { assert: {} }),
36+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING' }
37+
);
38+
39+
await rejects(
40+
import(jsonModuleDataUrl, { assert: { foo: 'bar' } }),
41+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_MISSING' }
42+
);
43+
44+
await rejects(
45+
import(jsonModuleDataUrl, { assert: { type: 'unsupported' }}),
46+
{ code: 'ERR_IMPORT_ASSERTION_TYPE_FAILED' }
47+
);

test/fixtures/empty.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

0 commit comments

Comments
 (0)