source: Dev/branches/rest-dojo-ui/client/util/build/v1xProfiles.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

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