340 lines
12 KiB
JavaScript
340 lines
12 KiB
JavaScript
define([
|
|
"require",
|
|
"./buildControlBase",
|
|
"./fs", "./fileUtils"
|
|
], function(require, bc, fs, fileUtils){
|
|
eval(require.scopeify("./fs, ./fileUtils"));
|
|
var mix = function(dest, src){
|
|
dest = dest || {};
|
|
src = src || {};
|
|
for(var p in src) dest[p] = src[p];
|
|
return dest;
|
|
},
|
|
|
|
// any profile properties default values that are different in a 1.6- profile are listed below
|
|
defaultBuildProps = {
|
|
// these are computed explicitly in processProfile() below
|
|
//releaseName:"dojo",
|
|
//releaseDir:"../../release",
|
|
|
|
staticHasFeatures:{
|
|
// consider turning these hard on for standard 1.x build
|
|
//'config-publishRequireResult':1,
|
|
//'config-tlmSiblingOfDojo':1,
|
|
},
|
|
|
|
defaultConfig:{
|
|
// no changes
|
|
hasCache:{
|
|
// no changes
|
|
}
|
|
}
|
|
},
|
|
|
|
processProfile = function(profile, dojoPath, utilBuildscriptsPath, profilePath){
|
|
// process a v1.6- profile
|
|
//
|
|
// v1.6- has the following relative path behavior:
|
|
//
|
|
// * the util/buildscripts/ directory is assumed to be the cwd upon build program startup
|
|
// * the dojo directory as specified in profile dependencies.prefixes (if relative) is
|
|
// assumed to be relative to util/buildscripts/; usually, it is not explicitly specified
|
|
// and is automatically set by the v1.6 build application to ../../dojo.
|
|
// * similarly the releaseDir directory (if relative) is assumed to be relative to util/buildscripts/
|
|
// * all other relative paths are relative to the dojo directory (in spite of what some docs say)
|
|
// * all input module hierarchies are "flattened" so they are siblings of the dojo directory
|
|
//
|
|
// This has the net effect of forcing the assumption that build program is be executed from util/buildscripts.
|
|
// when relative paths are used; this may be inconvenient. The behavior is probably consequent to rhino's design
|
|
// that does not report the full path of the script being executed.
|
|
//
|
|
var
|
|
p,
|
|
result = {},
|
|
layers = profile.layers || [],
|
|
prefixes = profile.prefixes || [];
|
|
|
|
for(p in defaultBuildProps){
|
|
result[p] = defaultBuildProps[p];
|
|
}
|
|
for(p in profile){
|
|
if(/^(loader|xdDojoPath|scopeDjConfig|xdScopeArgs|xdDojoScopeName|expandProvide|buildLayers|query|removeDefaultNameSpaces|addGuards)$/.test(p)){
|
|
bc.log("inputDeprecated", ["switch", p]);
|
|
}else if(p=="staticHasFeatures"){
|
|
mix(result.staticHasFeatures, profile.staticHasFeatures);
|
|
}else if(p=="defaultConfig"){
|
|
for(p in profile.defaultConfig){
|
|
if(p=="hasCache"){
|
|
mix(result.defaultConfig.hasCache, profile.defaultConfig.hasCache);
|
|
}else{
|
|
result.defaultConfig[p] = profile.defaultConfig[p];
|
|
}
|
|
}
|
|
}else{
|
|
// this is gross, but it's in the v1.6 app...and it's used in some of our own profiles as of [26706]
|
|
result[p] = (profile[p]=="false" ? false : profile[p]);
|
|
}
|
|
}
|
|
|
|
// convert the prefix vector to a map
|
|
var prefixMap =
|
|
// map from top-level mid --> path
|
|
{},
|
|
copyrightMap =
|
|
// map from top-level mid --> copyright message (usually undefined)
|
|
{},
|
|
runtimeMap =
|
|
// map from top-level mid --> runtime environment for computing depenencies in transforms/depsScan (usually undefined)
|
|
{};
|
|
prefixes.forEach(function(pair){
|
|
// pair a [mid, path], mid, a top-level module id, path relative to dojo directory
|
|
var mid = pair[0];
|
|
prefixMap[mid]= pair[1];
|
|
// copyright is relaxed in 1.7+: it can be a string or a filename
|
|
copyrightMap[mid] = (pair[2] && (maybeRead(computePath(pair[2], utilBuildscriptsPath)) || maybeRead(computePath(pair[2], profilePath)) || pair[2])) || "";
|
|
runtimeMap[mid] = pair[3];
|
|
});
|
|
|
|
// make sure we have a dojo path; notice we default to the dojo being used to run the build program as per the v1.6- build system
|
|
// the only place basePath is used when processing a v1.6- profile is to compute releaseDir when releaseDir is relative
|
|
// in this case, basePath in v1.6- is always assumed to be /util/buildscripts
|
|
var basePath = result.basePath = utilBuildscriptsPath;
|
|
|
|
if(!prefixMap.dojo){
|
|
prefixMap.dojo = dojoPath;
|
|
}
|
|
// make sure it is absolute
|
|
prefixMap.dojo = computePath(prefixMap.dojo, basePath);
|
|
if(prefixMap.dojo!=dojoPath){
|
|
bc.log("buildUsingDifferentDojo");
|
|
}
|
|
dojoPath = prefixMap.dojo;
|
|
|
|
// now we can compute an absolute path for each prefix (top-level module)
|
|
// (recall , in v1.6-, relative prefix paths are relative to the dojo path because of "flattening"
|
|
for(var mid in prefixMap){
|
|
if(mid!="dojo"){
|
|
prefixMap[mid] = computePath(prefixMap[mid], dojoPath);
|
|
}
|
|
}
|
|
|
|
// now fixup and make absolute the releaseDir; releaseDir, if relative, is relative to /util/buildscripts
|
|
// by making it absolute, later profiles can change basePath without affecting releaseDir
|
|
result.releaseDir = computePath((profile.releaseDir || "../../release").replace(/\\/g, "/"), basePath);
|
|
|
|
// make sure releaseName is clean
|
|
if(typeof profile.releaseName == "undefined"){
|
|
profile.releaseName = "dojo";
|
|
}
|
|
if(!profile.releaseName){
|
|
profile.releaseName = "";
|
|
}
|
|
|
|
result.releaseName = profile.releaseName.replace(/\\/g, "/");
|
|
|
|
// now make a package for each top-level module
|
|
var packages = result.packages = [];
|
|
for(mid in prefixMap){
|
|
packages.push({
|
|
name:mid,
|
|
location:prefixMap[mid],
|
|
copyright:copyrightMap[mid]!==undefined ? copyrightMap[mid] : bc.defaultCopyright,
|
|
runtime:runtimeMap[mid]
|
|
});
|
|
}
|
|
|
|
// recall the v1.6- build system "flattens" the module structure, no matter how it is arranged on input, into a set of sibling
|
|
// top-level modules (dojo, dijit, dojox, demos, myStuff, yourStuff, etc.). The layer.name property is just a filename. Theoretically,
|
|
// it could be placed anywhere, but in practice, it's always places somewhere in this flattened forest of module trees by giving
|
|
// a name like "../myTopLevelModule/someModule.js". Therefore, the intendeded module name can be deduced by chopping off the "../"
|
|
// prefix and ".js" suffix. Again, in theory, this won't work 100% of the time, but we don't have any examples of it not working. This
|
|
// technique also works for layerDependencies. Therefore, transform a v1.6 layer object into a v1.7 layer object
|
|
var getLayerCopyrightMessage = function(explicit, mid){
|
|
// this is a bit obnoxious as a default, but it's the v1.6- behavior
|
|
// TODO: consider changing
|
|
if(explicit!==undefined){
|
|
return explicit;
|
|
}
|
|
var copyright = copyrightMap[mid.split('/',1)[0]];
|
|
if(copyright){
|
|
return copyright;
|
|
}else{
|
|
return bc.defaultCopyright + bc.defaultBuildNotice;
|
|
}
|
|
},
|
|
|
|
transformDependencies = function(list){
|
|
return list ? list.map(function(mid){
|
|
modulesSeen[mid = mid.replace(/\./g, "/")] = 1;
|
|
return mid;
|
|
}) : [];
|
|
},
|
|
|
|
transformLayerDependencies = function(list, layerName){
|
|
return list ? list.map(function(mid){
|
|
if(!/\//.test(mid) && !/\.js$/.test(mid)){
|
|
// not a slash and doesn't end in .js; therefore, must be a module name
|
|
modulesSeen[mid.split(".")[0]] = 1;
|
|
return mid;
|
|
}
|
|
var match;
|
|
if(/^\.\//.test(mid)){
|
|
mid = mid.substring(2);
|
|
}
|
|
if(mid=="dojo/dojo"){
|
|
return mid;
|
|
}else if(mid=="dojo.js"){
|
|
return "dojo/dojo";
|
|
}else if((match = mid.match(nameRe))){
|
|
// sibling of dojo
|
|
modulesSeen[match[1]] = 1;
|
|
return match[1];
|
|
}else if((match = mid.match(dojoModuleRe))){
|
|
// assuming a dojo module
|
|
bc.log("assumeLayerDependencyIsDojoModule", ["layer dependency", mid]);
|
|
return match[1];
|
|
}else{
|
|
bc.log("cannotDeduceModuleIdFrom16LayerDependency", ["layer name", layerName, "layer dependency name", mid]);
|
|
return "error";
|
|
}
|
|
}) : [];
|
|
},
|
|
|
|
nameRe = /^\.\.\/([^\.].*)\.js$/,
|
|
|
|
dojoModuleRe = /^([^\.].*)\.js$/,
|
|
|
|
modulesSeen = {},
|
|
|
|
fixedLayers = {};
|
|
layers.forEach(function(layer){
|
|
var match, name;
|
|
if(layer.resourceName){
|
|
name = layer.resourceName.replace(/\./g, "/");
|
|
}else{
|
|
name = layer.name;
|
|
if(/^\.\//.test(name)){
|
|
name = name.substring(2);
|
|
}
|
|
if(layer.name=="dojo.js"){
|
|
// custom base
|
|
name = "dojo/dojo";
|
|
if(!layer.customBase){
|
|
layer.dependencies.push("dojo/main");
|
|
}
|
|
layer.boot = true;
|
|
}else if((match = name.match(nameRe))){
|
|
// sibling of dojo
|
|
name = match[1];
|
|
}else if((match = name.match(dojoModuleRe))){
|
|
// hopefully a dojo module
|
|
name = "dojo/" + match[1];
|
|
bc.log("assumeLayerIsDojoModule", ["layer name", layer.name]);
|
|
}else{
|
|
bc.log("cannotDeduceModuleIdFrom16LayerName", ["layer name", layer.name]);
|
|
}
|
|
}
|
|
layer.include = transformDependencies(layer.dependencies);
|
|
layer.exclude = transformLayerDependencies(layer.layerDependencies, layer.name);
|
|
if(name!="dojo/dojo" && !layer.customBase){
|
|
layer.exclude.push("dojo/dojo");
|
|
}
|
|
layer.name = name;
|
|
modulesSeen[name.split("/")[0]] = 1;
|
|
layer.copyright = getLayerCopyrightMessage(layer.copyright, name);
|
|
fixedLayers[name] = layer;
|
|
});
|
|
|
|
// lastly, check that all the top-level module seen were in the prefixes vector
|
|
for(p in modulesSeen){
|
|
var tlm = p.split("/")[0];
|
|
if(!prefixMap[tlm]){
|
|
bc.log("missingPrefix", ["top-level module", tlm]);
|
|
}
|
|
}
|
|
result.layers = fixedLayers;
|
|
|
|
return result;
|
|
},
|
|
|
|
processHtmlFiles = function(files, dojoPath, utilBuildscriptsPath){
|
|
bc.log("processHtmlFiles", ["files", files.join(", ")]);
|
|
var
|
|
basePath = "",
|
|
layers = {},
|
|
prefix = "",
|
|
prefixes = {dijit: true, dojox: true};
|
|
files.forEach(function(htmlFile){
|
|
var
|
|
priorLayers = [],
|
|
addLayer = function(scriptName){
|
|
if(layers[scriptName]){
|
|
// if this module has been added before, find the intersection of dependencies
|
|
layers[scriptName] = layers[scriptName].filter(function(scriptName){
|
|
return priorLayers.indexOf(scriptName) > -1;
|
|
});
|
|
}else{
|
|
layers[scriptName] = priorLayers.concat();
|
|
}
|
|
if(scriptName.indexOf('.') > -1){
|
|
prefixes[scriptName.substring(scriptName, scriptName.indexOf('.'))] = true;
|
|
}
|
|
priorLayers.push(scriptName);
|
|
};
|
|
|
|
var html = fs.readFileSync(htmlFile, "utf8");
|
|
html.replace(/<script [^>]*src=["']([^'"]+)["']/gi, function(t, scriptName){
|
|
// for each script tag
|
|
if(scriptName.indexOf("dojo/dojo.js") > -1){
|
|
// use dojo.js to determine the prefix for our namespaces
|
|
prefix = scriptName.substring(0, scriptName.indexOf("dojo/dojo.js"));
|
|
|
|
// the release dir is relative to the dir that contains the html file(s)
|
|
// the prefix, if relative, is relative to basePath
|
|
if(!basePath){
|
|
basePath = fileUtils.getFilepath(htmlFile);
|
|
}
|
|
}else{
|
|
// non-dojo.js script files, add it to our list of layers
|
|
addLayer(scriptName = scriptName.substring(prefix.length, scriptName.length - 3).replace(/\//g, '.'));
|
|
}
|
|
});
|
|
html.replace(/dojo\.require\(["']([^'"]+)["']\)/g, function(t, scriptName){
|
|
// for each dojo.require call add it to the layers as well
|
|
addLayer(scriptName);
|
|
});
|
|
});
|
|
|
|
var prefixPaths = [];
|
|
// normalize the prefixes into the arrays that the build expects
|
|
for(prefix in prefixes){
|
|
prefixPaths.push([prefix, "../" + prefix]);
|
|
}
|
|
var layersArray = [];
|
|
for(var name in layers){
|
|
// for each layer, create a layer object
|
|
layersArray.push({
|
|
name: "../" + name.replace(/\./g,'/') + ".js", // use filename
|
|
dependencies: [
|
|
name.replace(/\//g,'.') // use module name
|
|
],
|
|
//use all previous layers as layer dependencies
|
|
layerDependencies: layers[name].map(function(name){
|
|
return "../" + name.replace(/\./g,'/') + ".js";
|
|
})
|
|
});
|
|
}
|
|
var profileProperties = {
|
|
layers: layersArray,
|
|
prefixes: prefixPaths,
|
|
basePath:basePath
|
|
};
|
|
return processProfile(profileProperties, dojoPath, utilBuildscriptsPath);
|
|
};
|
|
|
|
return {
|
|
processProfile:processProfile,
|
|
processHtmlFiles:processHtmlFiles
|
|
};
|
|
});
|