source: Dev/branches/rest-dojo-ui/client/util/build/discover.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: 8.0 KB
Line 
1define(["./buildControl", "./fileUtils", "./fs", "./stringify", "dojo/has", "./process"], function(bc, fileUtils, fs, stringify, has, process){
2        // find all files as given by files, dirs, trees, and packages
3        var
4                dirsProcessed =
5                        // a set of the directory names that have been inspected
6                        {},
7
8                treesDirsFiles = ["trees", "dirs", "files"],
9
10                srcDirs = {},
11
12                destDirs = {},
13
14                getFilepath = fileUtils.getFilepath,
15                catPath = fileUtils.catPath,
16                compactPath = fileUtils.compactPath,
17
18                start = function(resource, tagResource){
19                        if(!resource.tag){
20                                resource.tag = {};
21                        }
22                        if(tagResource){
23                                tagResource(resource);
24                        }
25                        bc.start(resource);
26                        srcDirs[getFilepath(resource.src)] = 1;
27                        destDirs[getFilepath(resource.dest)] = 1;
28                },
29
30                getResourceTagFunction = function(resourceTags){
31                        //resource tags is a map from tag to a function or a regular expression
32                        var getFilterFunction = function(item){
33                                        return typeof item=="function" ?
34                                                item :
35                                                function(filename){
36                                                        return item.test(filename);
37                                                };
38                                },
39                                tag = {},
40                                gotOne  = false;
41                        for(var p in resourceTags){
42                                tag[p] = getFilterFunction(resourceTags[p]);
43                                gotOne  = true;
44                        }
45                        if(!gotOne){
46                                return 0;
47                        }
48                        return function(resource){
49                                for(var p in tag){
50                                        if(tag[p](resource.src, resource.mid, resource)){
51                                                resource.tag[p] = 1;
52                                        }
53                                }
54                        };
55                },
56
57                neverExclude = function(){
58                        return 0;
59                },
60
61                getExcludes = function(excludes){
62                        // excludes is falsy, a function, or a regulare expression
63                        if(!excludes){
64                                return neverExclude;
65                        }else if(typeof excludes=="function"){
66                                return excludes;
67                        }else{
68                                return function(filename){
69                                        return excludes.test(filename);
70                                };
71                        }
72                },
73
74                readSingleDir = function(srcPath, destPath, excludes, advise, traverse){
75                        if(dirsProcessed[srcPath]){
76                                return;
77                        }
78                        dirsProcessed[srcPath] = 1;
79                        if(!fileUtils.dirExists(srcPath)){
80                                bc.log("missingDirDuringDiscovery", ["directory", srcPath]);
81                                return;
82                        }
83                        var
84                                srcPathLength = srcPath.length,
85                                subdirs = [];
86                        fs.readdirSync(srcPath).forEach(function(filename){
87                                var fullFilename = srcPath + "/" + filename;
88                                if(!excludes || !excludes(fullFilename)){
89                                        var stats = fs.statSync(fullFilename);
90                                        if(stats.isDirectory()){
91                                                subdirs.push(fullFilename);
92                                        }else{
93                                                advise(fullFilename, destPath + "/" + filename);
94                                        }
95                                }
96                        });
97                        if(traverse && subdirs.length){
98                                subdirs.forEach(function(path){
99                                        readSingleDir(path, destPath + path.substring(srcPathLength), excludes, advise, 1);
100                                });
101                        }
102                },
103
104                readFile = function(item, advise){
105                        advise(item[0], item[1]);
106                },
107
108                readDir = function(item, advise){
109                        readSingleDir(item[0], item[1], getExcludes(item[2]), advise, 0, 0);
110                },
111
112                readTree = function(item, advise){
113                        readSingleDir(item[0], item[1], getExcludes(item[2]), advise, 1);
114                },
115
116                discover = {
117                        files:readFile,
118                        dirs:readDir,
119                        trees:readTree
120                },
121
122                processPackage = function(pack, destPack){
123                        // treeItem is the package location tree; it may give explicit exclude instructions
124                        var treeItem;
125                        for(var trees = pack.trees || [], i = 0; i<trees.length; i++){
126                                if(trees[i][0]==pack.location){
127                                        treeItem = trees[i];
128                                        break;
129                                }
130                        }
131                        if(!treeItem){
132                                // create a tree item; don't traverse into hidden, backup, etc. files (e.g., .svn, .git, etc.)
133                                treeItem = [pack.location, destPack.location, /(\/\.)|(~$)/];
134                        }
135
136                        var filenames = [];
137                        readTree(treeItem, function(filename){ filenames.push(filename); });
138
139                        // next, sift filenames to find AMD modules
140                        var
141                                maybeAmdModules = {},
142                                notModules = {},
143                                locationPathLength = pack.location.length + 1,
144                                packName = pack.name,
145                                prefix = packName ? packName + "/" : "",
146                                mainModuleInfo = packName && bc.getSrcModuleInfo(packName),
147                                mainModuleFilename = packName && mainModuleInfo.url;
148                        filenames.forEach(function(filename){
149                                // strip the package location path and the .js suffix(iff any) to get the mid
150                                var
151                                        maybeModule = /\.js$/.test(filename),
152                                        mid = prefix + filename.substring(locationPathLength, maybeModule ? filename.length-3 : filename.length),
153                                        moduleInfo = maybeModule && bc.getSrcModuleInfo(mid);
154                                if(!maybeModule){
155                                        notModules[mid] = [filename, mid];
156                                }else if(filename==mainModuleFilename){
157                                        maybeAmdModules[packName] = mainModuleInfo;
158                                }else{
159                                        maybeAmdModules[mid] = moduleInfo;
160                                }
161                        });
162
163                        // add modules as per explicit pack.modules vector; this is a way to add modules that map strangely
164                        // (for example "myPackage/foo" maps to the file "myPackage/bar"); recall, packageInfo.modules has two forms:
165                        //
166                        //       modules:{
167                        //               "foo":1,
168                        //               "foo":"path/to/foo/filename.js"
169                        //       }
170                        for(var mid in pack.modules){
171                                var
172                                        fullMid = prefix + mid,
173                                        moduleInfo = bc.getSrcModuleInfo(fullMid);
174                                if(typeof pack.modules[mid]=="string"){
175                                        moduleInfo.url = pack.modules[mid];
176                                }
177                                maybeAmdModules[fullMid] = moduleInfo;
178                                delete notModules[fullMid];
179                        };
180
181                        var tagResource = getResourceTagFunction(pack.resourceTags);
182
183                        // start all the package modules; each property holds a module info object
184                        for(var p in maybeAmdModules){
185                                moduleInfo = maybeAmdModules[p];
186                                var resource = {
187                                        src:moduleInfo.url,
188                                        dest:bc.getDestModuleInfo(moduleInfo.mid).url,
189                                        pid:moduleInfo.pid,
190                                        mid:moduleInfo.mid,
191                                        pack:pack,
192                                        deps:[]
193                                };
194                                start(resource, tagResource);
195                        }
196
197                        // start all the "notModules"
198                        var prefixLength = prefix.length;
199                        for(p in notModules){
200                                resource = {
201                                        src:notModules[p][0],
202                                        // not really an AMD mid, but the filename with installation-dependent prefix stripped
203                                        // this makes tagging easier
204                                        mid:notModules[p][1],
205                                        dest:catPath(destPack.location, p.substring(prefixLength))
206                                };
207                                start(resource, tagResource);
208                        }
209
210                        // finish by processing all the trees, dirs, and files explicitly specified for the package
211                        for(i = 0; i<treesDirsFiles.length; i++){
212                                var set = treesDirsFiles[i];
213                                if(pack[set]){
214                                        pack[set].forEach(function(item){
215                                                discover[set](item, function(src, dest){
216                                                        start({src:src, dest:dest}, tagResource);
217                                                });
218                                        });
219                                }
220                        }
221                },
222
223                discoverPackages = function(){
224                        // discover all the package modules; discover the default package last since it may overlap
225                        // into other packages and we want modules in those other packages to be discovered as members
226                        // of those other packages; not as a module in the default package
227                        for(var p in bc.packages){
228                                processPackage(bc.packages[p], bc.destPackages[p]);
229                        }
230                };
231
232        return function(){
233                ///
234                // build/discover
235
236                bc.waiting++; // matches *1*
237
238                // start the synthetic report resource
239                start({
240                        tag:{report:1},
241                        src:"*report",
242                        dest:"*report",
243                        reports:[]
244                });
245
246                discoverPackages();
247
248                // discover all trees, dirs, and files
249                var tagResource = getResourceTagFunction(bc.resourceTags);
250                for(var i = 0; i<treesDirsFiles.length; i++){
251                        var set = treesDirsFiles[i];
252                        bc[set].forEach(function(item){
253                                discover[set](item, function(src, dest){
254                                        start({src:src, dest:dest}, tagResource);
255                                });
256                        });
257                }
258
259                // advise all modules that are to be written as a layer
260                // advise the loader of boot layers
261                for(var mid in bc.layers){
262                        var
263                                layer = bc.layers[mid],
264                                moduleInfo = bc.getSrcModuleInfo(mid),
265                                resource = bc.resources[moduleInfo.url];
266                        if(!resource){
267                                // this is a synthetic layer (just a set of real modules aggregated but doesn't exist in the source)
268                                resource = {
269                                        tag:{synthetic:1, amd:1},
270                                        src:moduleInfo.url,
271                                        dest:bc.getDestModuleInfo(moduleInfo.mid).url,
272                                        pid:moduleInfo.pid,
273                                        mid:moduleInfo.mid,
274                                        pack:moduleInfo.pack,
275                                        deps:[],
276                                        text:"define([], 1);\n",
277                                        getText:function(){
278                                                return this.text;
279                                        },
280                                        encoding:"utf8"
281                                };
282                                start(resource);
283                        }
284                        resource.layer = layer;
285                        if(layer.boot){
286                                if(bc.loader){
287                                        bc.loader.boots.push(resource);
288                                }else{
289                                        bc.log("inputNoLoaderForBoot", ["boot layer", mid]);
290                                }
291                        }
292                }
293
294                bc.passGate(); // matches *1*
295        };
296});
Note: See TracBrowser for help on using the repository browser.