in harness/curl.js [980:1113]
fetchDep: function (depName, parentDef) {
var toAbsId, isPreload, parentCfg, parts, absId, mainId, loaderId, pluginId,
resId, pathInfo, def, tempDef, resCfg;
toAbsId = parentDef.toAbsId;
isPreload = parentDef.isPreload;
parentCfg = parentDef.config || userCfg; // is this fallback necessary?
absId = toAbsId(depName);
if (absId in cache) {
// module already exists in cache
mainId = absId;
}
else {
// check for plugin loaderId
parts = pluginParts(absId);
resId = parts.resourceId;
// get id of first resource to load (which could be a plugin)
mainId = parts.pluginId || resId;
pathInfo = core.resolvePathInfo(mainId, parentCfg);
}
if (!(absId in cache)) {
resCfg = core.resolvePathInfo(resId, parentCfg).config;
if (parts.pluginId) {
loaderId = mainId;
}
else {
// get custom module loader from package config if not a plugin
// TODO: move config.moduleLoader to config.loader
loaderId = resCfg['moduleLoader'] || resCfg.moduleLoader
|| resCfg['loader'] || resCfg.loader;
if (loaderId) {
// TODO: allow transforms to have relative module ids?
// (we could do this by returning package location from
// resolvePathInfo. why not return all package info?)
resId = mainId;
mainId = loaderId;
pathInfo = core.resolvePathInfo(loaderId, parentCfg);
}
}
}
if (mainId in cache) {
def = cache[mainId];
}
else if (pathInfo.url in urlCache) {
def = cache[mainId] = urlCache[pathInfo.url];
}
else {
def = core.createResourceDef(resCfg, mainId, isPreload);
// TODO: can this go inside createResourceDef?
// TODO: can we pass pathInfo.url to createResourceDef instead?
def.url = core.checkToAddJsExt(pathInfo.url, pathInfo.config);
cache[mainId] = urlCache[pathInfo.url] = def;
core.fetchResDef(def);
}
// plugin or transformer
if (mainId == loaderId) {
// use plugin's config if specified
if (parts.pluginId && parentCfg.plugins[parts.pluginId]) {
resCfg = parentCfg.plugins[parts.pluginId];
}
// we need to use an anonymous promise until plugin tells
// us normalized id. then, we need to consolidate the promises
// below. Note: exports objects will be different between
// pre-normalized and post-normalized defs! does this matter?
// don't put this resource def in the cache because if the
// resId doesn't change, the check if this is a new
// normalizedDef (below) will think it's already being loaded.
tempDef = new Promise();
// wait for plugin resource def
when(def, function(plugin) {
var normalizedDef, fullId, dynamic;
dynamic = plugin['dynamic'];
// check if plugin supports the normalize method
if ('normalize' in plugin) {
// note: dojo/has may return falsey values (0, actually)
resId = plugin['normalize'](resId, toAbsId, def.config) || '';
}
else {
resId = toAbsId(resId);
}
// use the full id (loaderId + id) to id plugin resources
// so multiple plugins may each process the same resource
// resId could be blank if the plugin doesn't require any (e.g. "domReady!")
fullId = loaderId + '!' + resId;
normalizedDef = cache[fullId];
// if this is our first time fetching this (normalized) def
if (!(fullId in cache)) {
// because we're using resId, plugins, such as wire!,
// can use paths relative to the resource
normalizedDef = core.createPluginDef(resCfg, fullId, resId, isPreload);
// don't cache non-determinate "dynamic" resources
if (!dynamic) {
cache[fullId] = normalizedDef;
}
// curl's plugins prefer to receive a deferred,
// but to be compatible with AMD spec, we have to
// piggy-back on the callback function parameter:
var loaded = function (res) {
if (!dynamic) cache[fullId] = res;
normalizedDef.resolve(res);
};
loaded['resolve'] = loaded;
loaded['reject'] = loaded['error'] = normalizedDef.reject;
// load the resource!
plugin.load(resId, normalizedDef.require, loaded, resCfg);
}
// chain defs (resolve when plugin.load executes)
if (tempDef != normalizedDef) {
when(normalizedDef, tempDef.resolve, tempDef.reject, tempDef.progress);
}
}, tempDef.reject);
}
// return tempDef if this is a plugin-based resource
return tempDef || def;
},