1 | /* -*- Mode: js; js-indent-level: 2; -*- */
|
2 | /*
|
3 | * Copyright 2011 Mozilla Foundation and contributors
|
4 | * Licensed under the New BSD license. See LICENSE or:
|
5 | * http://opensource.org/licenses/BSD-3-Clause
|
6 | */
|
7 |
|
8 | /**
|
9 | * Define a module along with a payload.
|
10 | * @param {string} moduleName Name for the payload
|
11 | * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec
|
12 | * @param {function} payload Function with (require, exports, module) params
|
13 | */
|
14 | function define(moduleName, deps, payload) {
|
15 | if (typeof moduleName != "string") {
|
16 | throw new TypeError('Expected string, got: ' + moduleName);
|
17 | }
|
18 |
|
19 | if (arguments.length == 2) {
|
20 | payload = deps;
|
21 | }
|
22 |
|
23 | if (moduleName in define.modules) {
|
24 | throw new Error("Module already defined: " + moduleName);
|
25 | }
|
26 | define.modules[moduleName] = payload;
|
27 | };
|
28 |
|
29 | /**
|
30 | * The global store of un-instantiated modules
|
31 | */
|
32 | define.modules = {};
|
33 |
|
34 |
|
35 | /**
|
36 | * We invoke require() in the context of a Domain so we can have multiple
|
37 | * sets of modules running separate from each other.
|
38 | * This contrasts with JSMs which are singletons, Domains allows us to
|
39 | * optionally load a CommonJS module twice with separate data each time.
|
40 | * Perhaps you want 2 command lines with a different set of commands in each,
|
41 | * for example.
|
42 | */
|
43 | function Domain() {
|
44 | this.modules = {};
|
45 | this._currentModule = null;
|
46 | }
|
47 |
|
48 | (function () {
|
49 |
|
50 | /**
|
51 | * Lookup module names and resolve them by calling the definition function if
|
52 | * needed.
|
53 | * There are 2 ways to call this, either with an array of dependencies and a
|
54 | * callback to call when the dependencies are found (which can happen
|
55 | * asynchronously in an in-page context) or with a single string an no callback
|
56 | * where the dependency is resolved synchronously and returned.
|
57 | * The API is designed to be compatible with the CommonJS AMD spec and
|
58 | * RequireJS.
|
59 | * @param {string[]|string} deps A name, or names for the payload
|
60 | * @param {function|undefined} callback Function to call when the dependencies
|
61 | * are resolved
|
62 | * @return {undefined|object} The module required or undefined for
|
63 | * array/callback method
|
64 | */
|
65 | Domain.prototype.require = function(deps, callback) {
|
66 | if (Array.isArray(deps)) {
|
67 | var params = deps.map(function(dep) {
|
68 | return this.lookup(dep);
|
69 | }, this);
|
70 | if (callback) {
|
71 | callback.apply(null, params);
|
72 | }
|
73 | return undefined;
|
74 | }
|
75 | else {
|
76 | return this.lookup(deps);
|
77 | }
|
78 | };
|
79 |
|
80 | function normalize(path) {
|
81 | var bits = path.split('/');
|
82 | var i = 1;
|
83 | while (i < bits.length) {
|
84 | if (bits[i] === '..') {
|
85 | bits.splice(i-1, 1);
|
86 | } else if (bits[i] === '.') {
|
87 | bits.splice(i, 1);
|
88 | } else {
|
89 | i++;
|
90 | }
|
91 | }
|
92 | return bits.join('/');
|
93 | }
|
94 |
|
95 | function join(a, b) {
|
96 | a = a.trim();
|
97 | b = b.trim();
|
98 | if (/^\//.test(b)) {
|
99 | return b;
|
100 | } else {
|
101 | return a.replace(/\/*$/, '/') + b;
|
102 | }
|
103 | }
|
104 |
|
105 | function dirname(path) {
|
106 | var bits = path.split('/');
|
107 | bits.pop();
|
108 | return bits.join('/');
|
109 | }
|
110 |
|
111 | /**
|
112 | * Lookup module names and resolve them by calling the definition function if
|
113 | * needed.
|
114 | * @param {string} moduleName A name for the payload to lookup
|
115 | * @return {object} The module specified by aModuleName or null if not found.
|
116 | */
|
117 | Domain.prototype.lookup = function(moduleName) {
|
118 | if (/^\./.test(moduleName)) {
|
119 | moduleName = normalize(join(dirname(this._currentModule), moduleName));
|
120 | }
|
121 |
|
122 | if (moduleName in this.modules) {
|
123 | var module = this.modules[moduleName];
|
124 | return module;
|
125 | }
|
126 |
|
127 | if (!(moduleName in define.modules)) {
|
128 | throw new Error("Module not defined: " + moduleName);
|
129 | }
|
130 |
|
131 | var module = define.modules[moduleName];
|
132 |
|
133 | if (typeof module == "function") {
|
134 | var exports = {};
|
135 | var previousModule = this._currentModule;
|
136 | this._currentModule = moduleName;
|
137 | module(this.require.bind(this), exports, { id: moduleName, uri: "" });
|
138 | this._currentModule = previousModule;
|
139 | module = exports;
|
140 | }
|
141 |
|
142 | // cache the resulting module object for next time
|
143 | this.modules[moduleName] = module;
|
144 |
|
145 | return module;
|
146 | };
|
147 |
|
148 | }());
|
149 |
|
150 | define.Domain = Domain;
|
151 | define.globalDomain = new Domain();
|
152 | var require = define.globalDomain.require.bind(define.globalDomain);
|