UNPKG

4.27 kBJavaScriptView Raw
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 */
14function 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 */
32define.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 */
43function 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
150define.Domain = Domain;
151define.globalDomain = new Domain();
152var require = define.globalDomain.require.bind(define.globalDomain);