| // Test importing module namespaces |
| |
| "use strict"; |
| |
| load(libdir + "asserts.js"); |
| load(libdir + "iteration.js"); |
| load(libdir + "dummyModuleResolveHook.js"); |
| |
| function parseAndEvaluate(source) { |
| let m = parseModule(source); |
| m.declarationInstantiation(); |
| return m.evaluation(); |
| } |
| |
| function testHasNames(names, expected) { |
| assertEq(names.length, expected.length); |
| expected.forEach(function(name) { |
| assertEq(names.includes(name), true); |
| }); |
| } |
| |
| let a = moduleRepo['a'] = parseModule("export var a = 1; export var b = 2;"); |
| let b = moduleRepo['b'] = parseModule("import * as ns from 'a'; var x = ns.a + ns.b;"); |
| b.declarationInstantiation(); |
| b.evaluation(); |
| testHasNames(getModuleEnvironmentNames(b), ["ns", "x"]); |
| let ns = getModuleEnvironmentValue(b, "ns"); |
| testHasNames(Object.keys(ns), ["a", "b"]); |
| assertEq(getModuleEnvironmentValue(b, "x"), 3); |
| |
| // Test module namespace internal methods as defined in 9.4.6 |
| assertEq(Object.getPrototypeOf(ns), null); |
| assertThrowsInstanceOf(() => Object.setPrototypeOf(ns, null), TypeError); |
| assertThrowsInstanceOf(function() { ns.foo = 1; }, TypeError); |
| assertEq(Object.isExtensible(ns), false); |
| Object.preventExtensions(ns); |
| let desc = Object.getOwnPropertyDescriptor(ns, "a"); |
| assertEq(desc.value, 1); |
| assertEq(desc.writable, true); |
| assertEq(desc.enumerable, true); |
| assertEq(desc.configurable, false); |
| assertEq(typeof desc.get, "undefined"); |
| assertEq(typeof desc.set, "undefined"); |
| assertThrowsInstanceOf(function() { ns.a = 1; }, TypeError); |
| delete ns.foo; |
| assertThrowsInstanceOf(function() { delete ns.a; }, TypeError); |
| |
| // Test @@iterator method. |
| let iteratorFun = ns[Symbol.iterator]; |
| assertEq(iteratorFun.name, "[Symbol.iterator]"); |
| |
| let iterator = ns[Symbol.iterator](); |
| assertEq(iterator[Symbol.iterator](), iterator); |
| assertIteratorNext(iterator, "a"); |
| assertIteratorNext(iterator, "b"); |
| assertIteratorDone(iterator); |
| |
| // The iterator's next method can only be called on the object it was originally |
| // associated with. |
| iterator = ns[Symbol.iterator](); |
| let iterator2 = ns[Symbol.iterator](); |
| assertThrowsInstanceOf(() => iterator.next.call({}), TypeError); |
| assertThrowsInstanceOf(() => iterator.next.call(iterator2), TypeError); |
| assertEq(iterator.next.call(iterator).value, "a"); |
| assertEq(iterator2.next.call(iterator2).value, "a"); |
| |
| // Test cyclic namespace import and access in module evaluation. |
| let c = moduleRepo['c'] = |
| parseModule("export let c = 1; import * as ns from 'd'; let d = ns.d;"); |
| let d = moduleRepo['d'] = |
| parseModule("export let d = 2; import * as ns from 'c'; let c = ns.c;"); |
| c.declarationInstantiation(); |
| d.declarationInstantiation(); |
| assertThrowsInstanceOf(() => c.evaluation(), ReferenceError); |
| |
| // Test cyclic namespace import. |
| let e = moduleRepo['e'] = |
| parseModule("export let e = 1; import * as ns from 'f'; export function f() { return ns.f }"); |
| let f = moduleRepo['f'] = |
| parseModule("export let f = 2; import * as ns from 'e'; export function e() { return ns.e }"); |
| e.declarationInstantiation(); |
| f.declarationInstantiation(); |
| e.evaluation(); |
| f.evaluation(); |
| assertEq(e.namespace.f(), 2); |
| assertEq(f.namespace.e(), 1); |