source: Dev/trunk/src/client/util/build/v1xProfiles.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 12.0 KB
Line 
1define([
2        "require",
3        "./buildControlBase",
4        "./fs", "./fileUtils"
5], function(require, bc, fs, fileUtils){
6        eval(require.scopeify("./fs, ./fileUtils"));
7        var mix = function(dest, src){
8                        dest = dest || {};
9                        src = src || {};
10                        for(var p in src) dest[p] = src[p];
11                        return dest;
12                },
13
14                // any profile properties default values that are different in a 1.6- profile are listed below
15                defaultBuildProps = {
16                        // these are computed explicitly in processProfile() below
17                        //releaseName:"dojo",
18                        //releaseDir:"../../release",
19
20                        staticHasFeatures:{
21                                // consider turning these hard on for standard 1.x build
22                                //'config-publishRequireResult':1,
23                                //'config-tlmSiblingOfDojo':1,
24                        },
25
26                        defaultConfig:{
27                                // no changes
28                                hasCache:{
29                                        // no changes
30                                }
31                        }
32                },
33
34                processProfile = function(profile, dojoPath, utilBuildscriptsPath, profilePath){
35                        // process a v1.6- profile
36                        //
37                        // v1.6- has the following relative path behavior:
38                        //
39                        //       * the util/buildscripts/ directory is assumed to be the cwd upon build program startup
40                        //       * the dojo directory as specified in profile dependencies.prefixes (if relative) is
41                        //         assumed to be relative to util/buildscripts/; usually, it is not explicitly specified
42                        //         and is automatically set by the v1.6 build application to ../../dojo.
43                        //       * similarly the releaseDir directory (if relative) is assumed to be relative to util/buildscripts/
44                        //       * all other relative paths are relative to the dojo directory (in spite of what some docs say)
45                        //       * all input module hierarchies are "flattened" so they are siblings of the dojo directory
46                        //
47                        // This has the net effect of forcing the assumption that build program is be executed from util/buildscripts.
48                        // when relative paths are used; this may be inconvenient. The behavior is probably consequent to rhino's design
49                        // that does not report the full path of the script being executed.
50                        //
51                        var
52                                p,
53                                result = {},
54                                layers = profile.layers || [],
55                                prefixes = profile.prefixes || [];
56
57                        for(p in defaultBuildProps){
58                                result[p] = defaultBuildProps[p];
59                        }
60                        for(p in profile){
61                                if(/^(loader|xdDojoPath|scopeDjConfig|xdScopeArgs|xdDojoScopeName|expandProvide|buildLayers|query|removeDefaultNameSpaces|addGuards)$/.test(p)){
62                                        bc.log("inputDeprecated", ["switch", p]);
63                                }else if(p=="staticHasFeatures"){
64                                        mix(result.staticHasFeatures, profile.staticHasFeatures);
65                                }else if(p=="defaultConfig"){
66                                        for(p in profile.defaultConfig){
67                                                if(p=="hasCache"){
68                                                        mix(result.defaultConfig.hasCache, profile.defaultConfig.hasCache);
69                                                }else{
70                                                        result.defaultConfig[p] = profile.defaultConfig[p];
71                                                }
72                                        }
73                                }else{
74                                        // this is gross, but it's in the v1.6 app...and it's used in some of our own profiles as of [26706]
75                                        result[p] = (profile[p]=="false" ? false : profile[p]);
76                                }
77                        }
78
79                        // convert the prefix vector to a map
80                        var prefixMap =
81                                        // map from top-level mid --> path
82                                        {},
83                                copyrightMap =
84                                        // map from top-level mid --> copyright message (usually undefined)
85                                        {},
86                                runtimeMap =
87                                        // map from top-level mid --> runtime environment for computing depenencies in transforms/depsScan (usually undefined)
88                                        {};
89                        prefixes.forEach(function(pair){
90                                // pair a [mid, path], mid, a top-level module id, path relative to dojo directory
91                                var mid = pair[0];
92                                prefixMap[mid]= pair[1];
93                                // copyright is relaxed in 1.7+: it can be a string or a filename
94                                copyrightMap[mid] = (pair[2] && (maybeRead(computePath(pair[2], utilBuildscriptsPath)) || maybeRead(computePath(pair[2], profilePath)) || pair[2])) || "";
95                                runtimeMap[mid] = pair[3];
96                        });
97
98                        // 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
99                        // the only place basePath is used when processing a v1.6- profile is to compute releaseDir when releaseDir is relative
100                        // in this case, basePath in v1.6- is always assumed to be /util/buildscripts
101                        var basePath = result.basePath = utilBuildscriptsPath;
102
103                        if(!prefixMap.dojo){
104                                prefixMap.dojo = dojoPath;
105                        }
106                        // make sure it is absolute
107                        prefixMap.dojo = computePath(prefixMap.dojo, basePath);
108                        if(prefixMap.dojo!=dojoPath){
109                                bc.log("buildUsingDifferentDojo");
110                        }
111                        dojoPath = prefixMap.dojo;
112
113                        // now we can compute an absolute path for each prefix (top-level module)
114                        // (recall , in v1.6-, relative prefix paths are relative to the dojo path because of "flattening"
115                        for(var mid in prefixMap){
116                                if(mid!="dojo"){
117                                        prefixMap[mid] = computePath(prefixMap[mid], dojoPath);
118                                }
119                        }
120
121                        // now fixup and make absolute the releaseDir; releaseDir, if relative, is relative to /util/buildscripts
122                        // by making it absolute, later profiles can change basePath without affecting releaseDir
123                        result.releaseDir = computePath((profile.releaseDir || "../../release").replace(/\\/g, "/"), basePath);
124
125                        // make sure releaseName is clean
126                        if(typeof profile.releaseName == "undefined"){
127                                profile.releaseName = "dojo";
128                        }
129                        if(!profile.releaseName){
130                                profile.releaseName = "";
131                        }
132
133                        result.releaseName = profile.releaseName.replace(/\\/g, "/");
134
135                        // now make a package for each top-level module
136                        var packages = result.packages = [];
137                        for(mid in prefixMap){
138                                packages.push({
139                                        name:mid,
140                                        location:prefixMap[mid],
141                                        copyright:copyrightMap[mid]!==undefined ? copyrightMap[mid] : bc.defaultCopyright,
142                                        runtime:runtimeMap[mid]
143                                });
144                        }
145
146                        // recall the v1.6- build system "flattens" the module structure, no matter how it is arranged on input, into a set of sibling
147                        // top-level modules (dojo, dijit, dojox, demos, myStuff, yourStuff, etc.). The layer.name property is just a filename. Theoretically,
148                        // it could be placed anywhere, but in practice, it's always places somewhere in this flattened forest of module trees by giving
149                        // a name like "../myTopLevelModule/someModule.js". Therefore, the intendeded module name can be deduced by chopping off the "../"
150                        // 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
151                        // technique also works for layerDependencies. Therefore, transform a v1.6 layer object into a v1.7 layer object
152                        var getLayerCopyrightMessage = function(explicit, mid){
153                                        // this is a bit obnoxious as a default, but it's the v1.6- behavior
154                                        // TODO: consider changing
155                                        if(explicit!==undefined){
156                                                return explicit;
157                                        }
158                                        var copyright = copyrightMap[mid.split('/',1)[0]];
159                                        if(copyright){
160                                                return copyright;
161                                        }else{
162                                                return bc.defaultCopyright + bc.defaultBuildNotice;
163                                        }
164                                },
165
166                                transformDependencies = function(list){
167                                        return list ? list.map(function(mid){
168                                                modulesSeen[mid = mid.replace(/\./g, "/")] = 1;
169                                                return mid;
170                                        }) : [];
171                                },
172
173                                transformLayerDependencies = function(list, layerName){
174                                        return list ? list.map(function(mid){
175                                                if(!/\//.test(mid) && !/\.js$/.test(mid)){
176                                                        // not a slash and doesn't end in .js; therefore, must be a module name
177                                                        modulesSeen[mid.split(".")[0]] = 1;
178                                                        return mid;
179                                                }
180                                                var match;
181                                                if(/^\.\//.test(mid)){
182                                                        mid = mid.substring(2);
183                                                }
184                                                if(mid=="dojo/dojo"){
185                                                        return mid;
186                                                }else if(mid=="dojo.js"){
187                                                        return "dojo/dojo";
188                                                }else if((match = mid.match(nameRe))){
189                                                        // sibling of dojo
190                                                        modulesSeen[match[1]] = 1;
191                                                        return match[1];
192                                                }else if((match = mid.match(dojoModuleRe))){
193                                                        // assuming a dojo module
194                                                        bc.log("assumeLayerDependencyIsDojoModule", ["layer dependency", mid]);
195                                                        return match[1];
196                                                }else{
197                                                        bc.log("cannotDeduceModuleIdFrom16LayerDependency", ["layer name", layerName, "layer dependency name", mid]);
198                                                        return "error";
199                                                }
200                                        }) : [];
201                                },
202
203                                nameRe = /^\.\.\/([^\.].*)\.js$/,
204
205                                dojoModuleRe = /^([^\.].*)\.js$/,
206
207                                modulesSeen = {},
208
209                                fixedLayers = {};
210                        layers.forEach(function(layer){
211                                var match, name;
212                                if(layer.resourceName){
213                                        name = layer.resourceName.replace(/\./g, "/");
214                                }else{
215                                        name = layer.name;
216                                        if(/^\.\//.test(name)){
217                                                name = name.substring(2);
218                                        }
219                                        if(layer.name=="dojo.js"){
220                                                // custom base
221                                                name = "dojo/dojo";
222                                                if(!layer.customBase){
223                                                        layer.dependencies.push("dojo/main");
224                                                }
225                                                layer.boot = true;
226                                        }else if((match = name.match(nameRe))){
227                                                // sibling of dojo
228                                                name = match[1];
229                                        }else if((match = name.match(dojoModuleRe))){
230                                                // hopefully a dojo module
231                                                name = "dojo/" + match[1];
232                                                bc.log("assumeLayerIsDojoModule", ["layer name", layer.name]);
233                                        }else{
234                                                bc.log("cannotDeduceModuleIdFrom16LayerName", ["layer name", layer.name]);
235                                        }
236                                }
237                                layer.include = transformDependencies(layer.dependencies);
238                                layer.exclude = transformLayerDependencies(layer.layerDependencies, layer.name);
239                                if(name!="dojo/dojo" && !layer.customBase){
240                                        layer.exclude.push("dojo/dojo");
241                                }
242                                layer.name = name;
243                                modulesSeen[name.split("/")[0]] = 1;
244                                layer.copyright = getLayerCopyrightMessage(layer.copyright, name);
245                                fixedLayers[name] = layer;
246                        });
247
248                        // lastly, check that all the top-level module seen were in the prefixes vector
249                        for(p in modulesSeen){
250                                var tlm = p.split("/")[0];
251                                if(!prefixMap[tlm]){
252                                        bc.log("missingPrefix", ["top-level module", tlm]);
253                                }
254                        }
255                        result.layers = fixedLayers;
256
257                        return result;
258                },
259
260                processHtmlFiles = function(files, dojoPath, utilBuildscriptsPath){
261                        bc.log("processHtmlFiles", ["files", files.join(", ")]);
262                        var
263                                basePath = "",
264                                layers = {},
265                                prefix = "",
266                                prefixes = {dijit: true, dojox: true};
267                        files.forEach(function(htmlFile){
268                                var
269                                        priorLayers = [],
270                                        addLayer = function(scriptName){
271                                                if(layers[scriptName]){
272                                                // if this module has been added before, find the intersection of dependencies
273                                                        layers[scriptName] = layers[scriptName].filter(function(scriptName){
274                                                                return priorLayers.indexOf(scriptName) > -1;
275                                                        });
276                                                }else{
277                                                        layers[scriptName] = priorLayers.concat();
278                                                }
279                                                if(scriptName.indexOf('.') > -1){
280                                                        prefixes[scriptName.substring(scriptName, scriptName.indexOf('.'))] = true;
281                                                }
282                                                priorLayers.push(scriptName);
283                                        };
284
285                                var html = fs.readFileSync(htmlFile, "utf8");
286                                html.replace(/<script [^>]*src=["']([^'"]+)["']/gi, function(t, scriptName){
287                                        // for each script tag
288                                        if(scriptName.indexOf("dojo/dojo.js") > -1){
289                                                // use dojo.js to determine the prefix for our namespaces
290                                                prefix = scriptName.substring(0, scriptName.indexOf("dojo/dojo.js"));
291
292                                                // the release dir is relative to the dir that contains the html file(s)
293                                                // the prefix, if relative, is relative to basePath
294                                                if(!basePath){
295                                                        basePath = fileUtils.getFilepath(htmlFile);
296                                                }
297                                        }else{
298                                                // non-dojo.js script files, add it to our list of layers
299                                                addLayer(scriptName = scriptName.substring(prefix.length, scriptName.length - 3).replace(/\//g, '.'));
300                                        }
301                                });
302                                html.replace(/dojo\.require\(["']([^'"]+)["']\)/g, function(t, scriptName){
303                                        // for each dojo.require call add it to the layers as well
304                                        addLayer(scriptName);
305                                });
306                        });
307
308                        var prefixPaths = [];
309                        // normalize the prefixes into the arrays that the build expects
310                        for(prefix in prefixes){
311                                prefixPaths.push([prefix, "../" + prefix]);
312                        }
313                        var layersArray = [];
314                        for(var name in layers){
315                                // for each layer, create a layer object
316                                layersArray.push({
317                                        name: "../" + name.replace(/\./g,'/') + ".js", // use filename
318                                        dependencies: [
319                                                name.replace(/\//g,'.') // use module name
320                                        ],
321                                        //use all previous layers as layer dependencies
322                                        layerDependencies: layers[name].map(function(name){
323                                                return "../" + name.replace(/\./g,'/') + ".js";
324                                        })
325                                });
326                        }
327                        var profileProperties = {
328                                layers: layersArray,
329                                prefixes: prefixPaths,
330                                basePath:basePath
331                        };
332                        return processProfile(profileProperties, dojoPath, utilBuildscriptsPath);
333                };
334
335        return {
336                processProfile:processProfile,
337                processHtmlFiles:processHtmlFiles
338        };
339});
Note: See TracBrowser for help on using the repository browser.