|
|
|
/*
|
|
|
|
* Tests for CommonJS module environment bindings and scope behavior.
|
|
|
|
*
|
|
|
|
* A module environment is isolated from the global environment. Variable
|
|
|
|
* and function declarations do not pollute the global object (although
|
|
|
|
* plain assignments do). In the current implementation a module is wrapped
|
|
|
|
* inside a temporary function which provides the scope for the module.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*===
|
|
|
|
basic bindings
|
|
|
|
modSearch: foo/bar
|
|
|
|
modSearch: foo/quux
|
|
|
|
require: function false
|
|
|
|
module: object foo/quux false false false
|
|
|
|
exports: object true
|
|
|
|
===*/
|
|
|
|
|
|
|
|
/* Check 'require', 'exports', and 'module'. */
|
|
|
|
|
|
|
|
var global_require = require;
|
|
|
|
|
|
|
|
Duktape.modSearch = function (id) {
|
|
|
|
print('modSearch:', id);
|
|
|
|
if (id === 'foo/bar') {
|
|
|
|
return 'var mod = require("./quux");\n'
|
|
|
|
}
|
|
|
|
if (id === 'foo/quux') {
|
|
|
|
return 'var pd;\n' +
|
|
|
|
'print("require:", typeof require, require === global_require);\n' +
|
|
|
|
'pd = Object.getOwnPropertyDescriptor(module, "id");\n' +
|
|
|
|
'print("module:", typeof module, module.id, pd.writable, pd.enumerable, pd.configurable);\n' +
|
|
|
|
'print("exports:", typeof exports, exports === this);\n'
|
|
|
|
;
|
|
|
|
}
|
|
|
|
throw new Error('cannot find module');
|
|
|
|
};
|
|
|
|
|
|
|
|
print('basic bindings');
|
|
|
|
|
|
|
|
function bindingTest() {
|
|
|
|
var mod = require('foo/bar');
|
|
|
|
|
|
|
|
// module.id must be a resolved absolute path so that it can be used
|
|
|
|
// to require the correct module from any other module
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
bindingTest();
|
|
|
|
} catch (e) {
|
|
|
|
print(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===
|
|
|
|
scoping
|
|
|
|
before global require
|
|
|
|
module: global-module
|
|
|
|
exports: global-exports
|
|
|
|
myVar1: global-myVar1
|
|
|
|
myVar2: global-myVar2
|
|
|
|
myVar3: global-myVar3
|
|
|
|
foo: global-foo
|
|
|
|
mod: object [object Object]
|
|
|
|
mod.name: test1
|
|
|
|
mod.foo: bar
|
|
|
|
after global require
|
|
|
|
module: global-module
|
|
|
|
exports: global-exports
|
|
|
|
myVar1: global-myVar1
|
|
|
|
myVar2: global-myVar2
|
|
|
|
myVar3: module-myVar3
|
|
|
|
foo: global-foo
|
|
|
|
before module require
|
|
|
|
module: global-module
|
|
|
|
exports: global-exports
|
|
|
|
myVar1: global-myVar1
|
|
|
|
myVar2: global-myVar2
|
|
|
|
myVar3: global-myVar3
|
|
|
|
foo: global-foo
|
|
|
|
mod: object [object Object]
|
|
|
|
mod.name: test2
|
|
|
|
mod.foo: bar
|
|
|
|
after module require
|
|
|
|
module: global-module
|
|
|
|
exports: global-exports
|
|
|
|
myVar1: global-myVar1
|
|
|
|
myVar2: global-myVar2
|
|
|
|
myVar3: module-myVar3
|
|
|
|
foo: global-foo
|
|
|
|
===*/
|
|
|
|
|
|
|
|
/* Assignment / scope tests. */
|
|
|
|
|
|
|
|
// These shouldn't get overwritten.
|
|
|
|
var module;
|
|
|
|
var exports;
|
|
|
|
var myVar1;
|
|
|
|
var myVar2;
|
|
|
|
var foo;
|
|
|
|
|
|
|
|
// This is ovwritten because module doesn't declare a variable
|
|
|
|
var myVar3;
|
|
|
|
|
|
|
|
// Temp
|
|
|
|
var mod;
|
|
|
|
|
|
|
|
function initVars() {
|
|
|
|
module = 'global-module';
|
|
|
|
exports = 'global-exports';
|
|
|
|
myVar1 = 'global-myVar1';
|
|
|
|
myVar2 = 'global-myVar2';
|
|
|
|
myVar3 = 'global-myVar3';
|
|
|
|
foo = 'global-foo';
|
|
|
|
}
|
|
|
|
|
|
|
|
function dumpVars() {
|
|
|
|
print('module:', module);
|
|
|
|
print('exports:', exports);
|
|
|
|
print('myVar1:', myVar1);
|
|
|
|
print('myVar2:', myVar2);
|
|
|
|
print('myVar3:', myVar3);
|
|
|
|
print('foo:', foo);
|
|
|
|
}
|
|
|
|
|
|
|
|
Duktape.modSearch = function (id) {
|
|
|
|
var ret;
|
|
|
|
|
|
|
|
if (id === 'test1' || id === 'test2') {
|
|
|
|
ret = 'var myVar1;\n' + // declared inside the module
|
|
|
|
'exports.name = "' + id + '";\n' + // goes into exports
|
|
|
|
'exports = "module-exports";\n' + // overwrites module exports, not global, does not affect exports.name getting exported
|
|
|
|
'this.foo = "bar";\n' + // 'this' is bound to the original exports table, so 'foo' gets exported
|
|
|
|
'require = "module-require";\n' + // overwrite module require, not global
|
|
|
|
'myVar1 = "module-myVar1";\n' + // writes to local variable, not global
|
|
|
|
'function myVar2() {}\n' + // declared inside module
|
|
|
|
'myVar3 = "module-myVar3";\n' // not declared locally, *set to global variable*
|
|
|
|
;
|
|
|
|
//print(ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
throw new Error('cannot find module: ' + id);
|
|
|
|
};
|
|
|
|
|
|
|
|
function moduleEnvironmentTest() {
|
|
|
|
var mod;
|
|
|
|
mod = require('test2');
|
|
|
|
print('mod:', typeof mod, mod);
|
|
|
|
print('mod.name:', mod.name);
|
|
|
|
print('mod.foo:', mod.foo);
|
|
|
|
print('after module require');
|
|
|
|
dumpVars();
|
|
|
|
}
|
|
|
|
|
|
|
|
print('scoping');
|
|
|
|
|
|
|
|
/* Using a require() from a global program. */
|
|
|
|
print('before global require');
|
|
|
|
initVars();
|
|
|
|
dumpVars();
|
|
|
|
try {
|
|
|
|
mod = require('test1');
|
|
|
|
} catch (e) {
|
|
|
|
print('global require failed:', e);
|
|
|
|
print(e.stack || e);
|
|
|
|
}
|
|
|
|
print('mod:', typeof mod, mod);
|
|
|
|
print('mod.name:', mod.name);
|
|
|
|
print('mod.foo:', mod.foo);
|
|
|
|
print('after global require');
|
|
|
|
dumpVars();
|
|
|
|
|
|
|
|
initVars();
|
|
|
|
print('before module require');
|
|
|
|
dumpVars();
|
|
|
|
|
|
|
|
try {
|
|
|
|
moduleEnvironmentTest();
|
|
|
|
} catch (e) {
|
|
|
|
print(e);
|
|
|
|
}
|