diff options
Diffstat (limited to 'lib/amd-helpers.js')
-rw-r--r-- | lib/amd-helpers.js | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/lib/amd-helpers.js b/lib/amd-helpers.js new file mode 100644 index 000000000..8a5b410c1 --- /dev/null +++ b/lib/amd-helpers.js @@ -0,0 +1,245 @@ +/* + * AMD Helper function module + * Separated into its own file as this is the part needed for full AMD support in SFX builds + * NB since implementations have now diverged this can be merged back with amd.js + */ + +hook('fetch', function(fetch) { + return function(load) { + // script load implies define global leak + if (load.metadata.scriptLoad && isBrowser) + __global.define = this.amdDefine; + return fetch.call(this, load); + }; +}); + +hookConstructor(function(constructor) { + return function() { + var loader = this; + constructor.call(this); + + var commentRegEx = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg; + var cjsRequirePre = "(?:^|[^$_a-zA-Z\\xA0-\\uFFFF.])"; + var cjsRequirePost = "\\s*\\(\\s*(\"([^\"]+)\"|'([^']+)')\\s*\\)"; + var fnBracketRegEx = /\(([^\)]*)\)/; + var wsRegEx = /^\s+|\s+$/g; + + var requireRegExs = {}; + + function getCJSDeps(source, requireIndex) { + + // remove comments + source = source.replace(commentRegEx, ''); + + // determine the require alias + var params = source.match(fnBracketRegEx); + var requireAlias = (params[1].split(',')[requireIndex] || 'require').replace(wsRegEx, ''); + + // find or generate the regex for this requireAlias + var requireRegEx = requireRegExs[requireAlias] || (requireRegExs[requireAlias] = new RegExp(cjsRequirePre + requireAlias + cjsRequirePost, 'g')); + + requireRegEx.lastIndex = 0; + + var deps = []; + + var match; + while (match = requireRegEx.exec(source)) + deps.push(match[2] || match[3]); + + return deps; + } + + /* + AMD-compatible require + To copy RequireJS, set window.require = window.requirejs = loader.amdRequire + */ + function require(names, callback, errback, referer) { + // in amd, first arg can be a config object... we just ignore + if (typeof names == 'object' && !(names instanceof Array)) + return require.apply(null, Array.prototype.splice.call(arguments, 1, arguments.length - 1)); + + // amd require + if (typeof names == 'string' && typeof callback == 'function') + names = [names]; + if (names instanceof Array) { + var dynamicRequires = []; + for (var i = 0; i < names.length; i++) + dynamicRequires.push(loader['import'](names[i], referer)); + Promise.all(dynamicRequires).then(function(modules) { + if (callback) + callback.apply(null, modules); + }, errback); + } + + // commonjs require + else if (typeof names == 'string') { + var defaultJSExtension = loader.defaultJSExtensions && names.substr(names.length - 3, 3) != '.js'; + var normalized = loader.decanonicalize(names, referer); + if (defaultJSExtension && normalized.substr(normalized.length - 3, 3) == '.js') + normalized = normalized.substr(0, normalized.length - 3); + var module = loader.get(normalized); + if (!module) + throw new Error('Module not already loaded loading "' + names + '" as ' + normalized + (referer ? ' from "' + referer + '".' : '.')); + return module.__useDefault ? module['default'] : module; + } + + else + throw new TypeError('Invalid require'); + } + + function define(name, deps, factory) { + if (typeof name != 'string') { + factory = deps; + deps = name; + name = null; + } + if (!(deps instanceof Array)) { + factory = deps; + deps = ['require', 'exports', 'module'].splice(0, factory.length); + } + + if (typeof factory != 'function') + factory = (function(factory) { + return function() { return factory; } + })(factory); + + // in IE8, a trailing comma becomes a trailing undefined entry + if (deps[deps.length - 1] === undefined) + deps.pop(); + + // remove system dependencies + var requireIndex, exportsIndex, moduleIndex; + + if ((requireIndex = indexOf.call(deps, 'require')) != -1) { + + deps.splice(requireIndex, 1); + + // only trace cjs requires for non-named + // named defines assume the trace has already been done + if (!name) + deps = deps.concat(getCJSDeps(factory.toString(), requireIndex)); + } + + if ((exportsIndex = indexOf.call(deps, 'exports')) != -1) + deps.splice(exportsIndex, 1); + + if ((moduleIndex = indexOf.call(deps, 'module')) != -1) + deps.splice(moduleIndex, 1); + + function execute(req, exports, module) { + var depValues = []; + for (var i = 0; i < deps.length; i++) + depValues.push(req(deps[i])); + + module.uri = module.id; + + module.config = function() {}; + + // add back in system dependencies + if (moduleIndex != -1) + depValues.splice(moduleIndex, 0, module); + + if (exportsIndex != -1) + depValues.splice(exportsIndex, 0, exports); + + if (requireIndex != -1) { + function contextualRequire(names, callback, errback) { + if (typeof names == 'string' && typeof callback != 'function') + return req(names); + return require.call(loader, names, callback, errback, module.id); + } + contextualRequire.toUrl = function(name) { + // normalize without defaultJSExtensions + var defaultJSExtension = loader.defaultJSExtensions && name.substr(name.length - 3, 3) != '.js'; + var url = loader.decanonicalize(name, module.id); + if (defaultJSExtension && url.substr(url.length - 3, 3) == '.js') + url = url.substr(0, url.length - 3); + return url; + }; + depValues.splice(requireIndex, 0, contextualRequire); + } + + // set global require to AMD require + var curRequire = __global.require; + __global.require = require; + + var output = factory.apply(exportsIndex == -1 ? __global : exports, depValues); + + __global.require = curRequire; + + if (typeof output == 'undefined' && module) + output = module.exports; + + if (typeof output != 'undefined') + return output; + } + + var entry = createEntry(); + entry.name = name && (loader.decanonicalize || loader.normalize).call(loader, name); + entry.deps = deps; + entry.execute = execute; + + loader.pushRegister_({ + amd: true, + entry: entry + }); + } + define.amd = {}; + + // reduction function to attach defines to a load record + hook('reduceRegister_', function(reduceRegister) { + return function(load, register) { + // only handle AMD registers here + if (!register || !register.amd) + return reduceRegister.call(this, load, register); + + var curMeta = load && load.metadata; + var entry = register.entry; + + if (curMeta) { + if (!curMeta.format || curMeta.format == 'detect') + curMeta.format = 'amd'; + else if (!entry.name && curMeta.format != 'amd') + throw new Error('AMD define called while executing ' + curMeta.format + ' module ' + load.name); + } + + // anonymous define + if (!entry.name) { + if (!curMeta) + throw new TypeError('Unexpected anonymous AMD define.'); + + if (curMeta.entry && !curMeta.entry.name) + throw new Error('Multiple anonymous defines in module ' + load.name); + + curMeta.entry = entry; + } + // named define + else { + // if we don't have any other defines, + // then let this be an anonymous define + // this is just to support single modules of the form: + // define('jquery') + // still loading anonymously + // because it is done widely enough to be useful + // as soon as there is more than one define, this gets removed though + if (curMeta) { + if (!curMeta.entry && !curMeta.bundle) + curMeta.entry = entry; + else if (curMeta.entry && curMeta.entry.name && curMeta.entry.name != load.name) + curMeta.entry = undefined; + + // note this is now a bundle + curMeta.bundle = true; + } + + // define the module through the register registry + if (!(entry.name in this.defined)) + this.defined[entry.name] = entry; + } + }; + }); + + loader.amdDefine = define; + loader.amdRequire = require; + }; +});
\ No newline at end of file |