Skip to content

Commit

Permalink
Merge pull request #126 from ember-cli/moduleId
Browse files Browse the repository at this point in the history
require.moduleId
  • Loading branch information
stefanpenner committed Jun 15, 2017
2 parents f62bc54 + 204838b commit db2f6a6
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 39 deletions.
21 changes: 21 additions & 0 deletions README.md
Expand Up @@ -31,6 +31,27 @@ require('foo') // => 'hi';
require('foo') === require('foo/bar/baz');
```

### `require('require')`

When within a module, one can require `require`. This provides a `require` scoped to the current module. Enabling dynamic, relatively path requires.

```js

define('foo/apple', ['require'], function() { return 'apple'; });
define('foo/bar', ['require'], function(require){ return require('./apple'););

require('foo/bar'); // 'apple';
```
This scoped `require` also enables a module some reflection, in this case the ability for a module to see its own `moduleId`;
```js

define('my/name/is', ['require'], function(require) {
require.moduleId // => 'my/name/is';
});
```
### `define.exports('foo', {})`
`define.exports` enables a fastpath for non-lazy dependency-less modules, for example:
Expand Down
67 changes: 34 additions & 33 deletions lib/loader/loader.js
Expand Up @@ -43,11 +43,11 @@ var loader, define, requireModule, require, requirejs;
requirejs: requirejs
};

requirejs = require = requireModule = function(name) {
requirejs = require = requireModule = function(id) {
var token = heimdall.start('require');
heimdall.increment(__require);
var pending = [];
var mod = findModule(name, '(require)', pending);
var mod = findModule(id, '(require)', pending);

for (var i = pending.length - 1; i >= 0; i--) {
pending[i].exports();
Expand Down Expand Up @@ -80,16 +80,16 @@ var loader, define, requireModule, require, requirejs;
var uuid = 0;

function unsupportedModule(length) {
throw new Error('an unsupported module was defined, expected `define(name, deps, module)` instead got: `' +
throw new Error('an unsupported module was defined, expected `define(id, deps, module)` instead got: `' +
length + '` arguments to define`');
}

var defaultDeps = ['require', 'exports', 'module'];

function Module(name, deps, callback, alias) {
function Module(id, deps, callback, alias) {
heimdall.increment(modules);
this.id = uuid++;
this.name = name;
this.uuid = uuid++;
this.id = id;
this.deps = !deps.length && callback.length ? defaultDeps : deps;
this.module = { exports: {} };
this.callback = callback;
Expand Down Expand Up @@ -126,7 +126,7 @@ var loader, define, requireModule, require, requirejs;
heimdall.increment(__exports);

if (loader.wrapModules) {
this.callback = loader.wrapModules(this.name, this.callback);
this.callback = loader.wrapModules(this.id, this.callback);
}

this.reify();
Expand Down Expand Up @@ -191,27 +191,28 @@ var loader, define, requireModule, require, requirejs;
} else if (dep === 'module') {
entry.exports = this.module;
} else {
entry.module = findModule(resolve(dep, this.name), this.name, pending);
entry.module = findModule(resolve(dep, this.id), this.id, pending);
}
}
};

Module.prototype.makeRequire = function() {
var name = this.name;
var id = this.id;
var r = function(dep) {
return require(resolve(dep, name));
return require(resolve(dep, id));
};
r['default'] = r;
r.moduleId = id;
r.has = function(dep) {
return has(resolve(dep, name));
return has(resolve(dep, id));
};
return r;
};

define = function(name, deps, callback) {
var module = registry[name];
define = function(id, deps, callback) {
var module = registry[id];

// If a module for this name has already been defined and is in any state
// If a module for this id has already been defined and is in any state
// other than `new` (meaning it has been or is currently being required),
// then we return early to avoid redefinition.
if (module && module.state !== 'new') {
Expand All @@ -230,9 +231,9 @@ var loader, define, requireModule, require, requirejs;
}

if (callback instanceof Alias) {
registry[name] = new Module(callback.name, deps, callback, true);
registry[id] = new Module(callback.id, deps, callback, true);
} else {
registry[name] = new Module(name, deps, callback, false);
registry[id] = new Module(id, deps, callback, false);
}
heimdall.stop(token);
};
Expand Down Expand Up @@ -260,31 +261,31 @@ var loader, define, requireModule, require, requirejs;
// we don't support all of AMD
// define.amd = {};

function Alias(path) {
this.name = path;
function Alias(id) {
this.id = id;
}

define.alias = function(path, target) {
define.alias = function(id, target) {
if (arguments.length === 2) {
return define(target, new Alias(path));
return define(target, new Alias(id));
}

return new Alias(path);
return new Alias(id);
};

function missingModule(name, referrer) {
throw new Error('Could not find module `' + name + '` imported from `' + referrer + '`');
function missingModule(id, referrer) {
throw new Error('Could not find module `' + id + '` imported from `' + referrer + '`');
}

function findModule(name, referrer, pending) {
function findModule(id, referrer, pending) {
heimdall.increment(__findModule);
var mod = registry[name] || registry[name + '/index'];
var mod = registry[id] || registry[id + '/index'];

while (mod && mod.isAlias) {
mod = registry[mod.name];
mod = registry[mod.id];
}

if (!mod) { missingModule(name, referrer); }
if (!mod) { missingModule(id, referrer); }

if (pending && mod.state !== 'pending' && mod.state !== 'finalized') {
mod.findDeps(pending);
Expand All @@ -294,13 +295,13 @@ var loader, define, requireModule, require, requirejs;
return mod;
}

function resolve(child, name) {
function resolve(child, id) {
heimdall.increment(__resolve);
if (child.charAt(0) !== '.') { return child; }
heimdall.increment(resolveRelative);

var parts = child.split('/');
var nameParts = name.split('/');
var nameParts = id.split('/');
var parentBase = nameParts.slice(0, -1);

for (var i = 0, l = parts.length; i < l; i++) {
Expand All @@ -319,14 +320,14 @@ var loader, define, requireModule, require, requirejs;
return parentBase.join('/');
}

function has(name) {
return !!(registry[name] || registry[name + '/index']);
function has(id) {
return !!(registry[id] || registry[id + '/index']);
}

requirejs.entries = requirejs._eak_seen = registry;
requirejs.has = has;
requirejs.unsee = function(moduleName) {
findModule(moduleName, '(unsee)', false).unsee();
requirejs.unsee = function(id) {
findModule(id, '(unsee)', false).unsee();
};

requirejs.clear = function() {
Expand Down
20 changes: 14 additions & 6 deletions tests/all.js
Expand Up @@ -8,8 +8,8 @@ var tree;
/**
* Simple helper to get the current state of a given module.
*/
function getModuleState(name) {
return requirejs.entries[name].state;
function getModuleState(id) {
return requirejs.entries[id].state;
}

function statsForMonitor(monitor, tree) {
Expand Down Expand Up @@ -141,7 +141,6 @@ test('simple define/require', function() {
deepEqual(Object.keys(requirejs.entries), ['foo']);
});


test('define without deps', function() {
var fooCalled = 0;

Expand Down Expand Up @@ -170,7 +169,6 @@ test('define without deps', function() {
deepEqual(Object.keys(requirejs.entries), ['foo']);
});


test('multiple define/require', function() {
define('foo', [], function() {

Expand Down Expand Up @@ -813,7 +811,7 @@ test('provides good error message when an un-named AMD module is provided', func
define(function() {

});
}, new Error('an unsupported module was defined, expected `define(name, deps, module)` instead got: `1` arguments to define`'));
}, new Error('an unsupported module was defined, expected `define(id, deps, module)` instead got: `1` arguments to define`'));
});


Expand Down Expand Up @@ -1418,7 +1416,7 @@ test('alias chaining with relative deps works', function() {
test('wrapModules is called when present', function() {
var fooCalled = 0;
var annotatorCalled = 0;
loader.wrapModules = function(name, callback) {
loader.wrapModules = function(id, callback) {
annotatorCalled++;
return callback;
};
Expand Down Expand Up @@ -1669,3 +1667,13 @@ test('define.exports', function(assert) {
define.exports('foo/bar', defaultExport);
assert.equal(require('foo/bar'), defaultExport);
});

test('require.moduleId', function(assert) {
define('foo', ['require'], function(require) {
assert.equal(require.moduleId, 'foo');
return require.moduleId;
});

define.alias('foo', 'foo/bar');
assert.equal(require('foo/bar'), 'foo');
});

0 comments on commit db2f6a6

Please sign in to comment.