vm: expose hasTopLevelAwait on SourceTextModule · nodejs/node@6e586a1

4 files changed

lines changed

Original file line numberDiff line numberDiff line change

@@ -920,6 +920,36 @@ to disallow any changes to it.

920920

Corresponds to the `[[RequestedModules]]` field of [Cyclic Module Record][]s in

921921

the ECMAScript specification.

922922
923+

### `sourceTextModule.hasAsyncGraph()`

924+
925+

<!-- YAML

926+

added: REPLACEME

927+

-->

928+
929+

* Returns: {boolean}

930+
931+

Iterates over the dependency graph and returns `true` if any module in its

932+

dependencies or this module itself contains top-level `await` expressions,

933+

otherwise returns `false`.

934+
935+

The search may be slow if the graph is big enough.

936+
937+

This requires the module to be instantiated first. If the module is not

938+

instantiated yet, an error will be thrown.

939+
940+

### `sourceTextModule.hasTopLevelAwait()`

941+
942+

<!-- YAML

943+

added: REPLACEME

944+

-->

945+
946+

* Returns: {boolean}

947+
948+

Returns whether the module itself contains any top-level `await` expressions.

949+
950+

This corresponds to the field `[[HasTLA]]` in [Cyclic Module Record][] in the

951+

ECMAScript specification.

952+
923953

### `sourceTextModule.instantiate()`

924954
925955

<!-- YAML

Original file line numberDiff line numberDiff line change

@@ -429,6 +429,19 @@ class SourceTextModule extends Module {

429429

return super.error;

430430

}

431431
432+

hasAsyncGraph() {

433+

validateThisInternalField(this, kWrap, 'SourceTextModule');

434+

if (this[kWrap].getStatus() < kInstantiated) {

435+

throw new ERR_VM_MODULE_STATUS('must be instantiated');

436+

}

437+

return this[kWrap].hasAsyncGraph;

438+

}

439+
440+

hasTopLevelAwait() {

441+

validateThisInternalField(this, kWrap, 'SourceTextModule');

442+

return this[kWrap].hasTopLevelAwait;

443+

}

444+
432445

createCachedData() {

433446

const { status } = this;

434447

if (status === 'evaluating' ||

Original file line numberDiff line numberDiff line change

@@ -0,0 +1,67 @@

1+

'use strict';

2+
3+

// Flags: --experimental-vm-modules

4+
5+

require('../common');

6+
7+

const assert = require('assert');

8+
9+

const { SourceTextModule } = require('vm');

10+

const test = require('node:test');

11+
12+

test('module is not instantiated yet', () => {

13+

const foo = new SourceTextModule(`

14+

export const foo = 4

15+

export default 5;

16+

`);

17+

assert.throws(() => foo.hasAsyncGraph(), {

18+

code: 'ERR_VM_MODULE_STATUS',

19+

});

20+

});

21+
22+

test('simple module with top-level await', () => {

23+

const foo = new SourceTextModule(`

24+

export const foo = 4

25+

export default 5;

26+
27+

await 0;

28+

`);

29+

foo.linkRequests([]);

30+

foo.instantiate();

31+
32+

assert.strictEqual(foo.hasAsyncGraph(), true);

33+

});

34+
35+

test('simple module with non top-level await', () => {

36+

const foo = new SourceTextModule(`

37+

export const foo = 4

38+

export default 5;

39+
40+

export async function f() {

41+

await 0;

42+

}

43+

`);

44+

foo.linkRequests([]);

45+

foo.instantiate();

46+
47+

assert.strictEqual(foo.hasAsyncGraph(), false);

48+

});

49+
50+

test('module with a dependency containing top-level await', () => {

51+

const foo = new SourceTextModule(`

52+

export const foo = 4

53+

export default 5;

54+
55+

await 0;

56+

`);

57+

foo.linkRequests([]);

58+
59+

const bar = new SourceTextModule(`

60+

export { foo } from 'foo';

61+

`);

62+

bar.linkRequests([foo]);

63+

bar.instantiate();

64+
65+

assert.strictEqual(foo.hasAsyncGraph(), true);

66+

assert.strictEqual(bar.hasAsyncGraph(), true);

67+

});

Original file line numberDiff line numberDiff line change

@@ -0,0 +1,59 @@

1+

'use strict';

2+
3+

// Flags: --experimental-vm-modules

4+
5+

require('../common');

6+
7+

const assert = require('assert');

8+
9+

const { SourceTextModule } = require('vm');

10+

const test = require('node:test');

11+
12+

test('simple module', () => {

13+

const foo = new SourceTextModule(`

14+

export const foo = 4

15+

export default 5;

16+

`);

17+

assert.strictEqual(foo.hasTopLevelAwait(), false);

18+

});

19+
20+

test('simple module with top-level await', () => {

21+

const foo = new SourceTextModule(`

22+

export const foo = 4

23+

export default 5;

24+
25+

await 0;

26+

`);

27+

assert.strictEqual(foo.hasTopLevelAwait(), true);

28+

});

29+
30+

test('simple module with non top-level await', () => {

31+

const foo = new SourceTextModule(`

32+

export const foo = 4

33+

export default 5;

34+
35+

export async function f() {

36+

await 0;

37+

}

38+

`);

39+

assert.strictEqual(foo.hasTopLevelAwait(), false);

40+

});

41+
42+

test('module with a dependency containing top-level await', () => {

43+

const foo = new SourceTextModule(`

44+

export const foo = 4

45+

export default 5;

46+
47+

await 0;

48+

`);

49+

foo.linkRequests([]);

50+
51+

const bar = new SourceTextModule(`

52+

export { foo } from 'foo';

53+

`);

54+

bar.linkRequests([foo]);

55+

bar.instantiate();

56+
57+

assert.strictEqual(foo.hasTopLevelAwait(), true);

58+

assert.strictEqual(bar.hasTopLevelAwait(), false);

59+

});