JSDOC/Packer.js
[gnome.introspection-doc-generator] / JSDOC / Packer.js
1 // <script type="text/javascript">
2 XObject = imports.XObject.XObject;
3 File = imports.File.File;
4
5 TokenReader = imports['JSDOC/TokenReader.js']/TokenReader;
6 /**
7  * @class JSDOC.Packer
8  * Create a new packer
9  * 
10  * Usage:
11  * <code>
12  *
13 var x = new JSDOC.Packer(
14     [ "/location/of/file1.js", "/location/of/file2.js", ... ],
15     "/location/of"
16 );
17 x.packFiles(
18     "/location/of/temp_batch_dir", 
19     "/location/of/output-compacted-file.js",
20     "/location/of/output-debug-merged-file.js"
21 );
22     
23  *</code> 
24  *
25  * Notes for improving compacting:
26  *  if you add a jsdoc comment 
27  * <code>
28  * /**
29  *   eval:var:avarname
30  *   eval:var:bvarname
31  *   ....
32  * </code>
33  * directly before an eval statement, it will compress all the code around the eval, 
34  * and not rename the variables 'avarname'
35  * 
36  * Dont try running this on a merged uncompressed large file - it's horrifically slow.
37  * Best to use lot's of small classes, and use it to merge, as it will cache the compaction
38  * 
39  * 
40  * 
41  * @param {Array} files List of Files - MUST BE WITH ABSOLUTE PATH eg. [ '/usr/src/xyz/abc.js', .... ]
42  * @param {String} source_path top level directory of source (used to work out the relative names for the minimized temp files)
43  */
44 Packer = function(files, spath)
45 {
46     this.files = files;
47     this.spath  = spath; // source path
48     this.aliasList = { }; // list of maps Roo.asdfasdfasf => Roo.A1
49     this.timer =  new Date() * 1;
50     this.translate = true;
51 }
52 Packer.prototype = {
53     
54     bpath : '',
55     
56     // set to false to stop translation happening..
57     
58     /**
59      * Pack the files.
60      * 
61      * @param {String} batch_path location of batched temporary min files.
62      * @param {String} compressed_file eg. roo-all.js
63      * @param {String} debug_file eg. roo-debug.js
64      * 
65      */
66     
67     packFiles : function(bpath, allfile, debugfile) {
68         var str;
69         var spath = this.spath;
70         var files = this.files;
71         this.bpath = bpath;
72         // old var names - fixme..
73         var dout = debugfile;
74         //File.write(dout, "");
75         
76         var outpath = allfile;
77       
78         var transfile = bpath + '/_translation_.js';
79         //this.transOrigFile= bpath + '/../lang.en.js'; // needs better naming...
80         //File.write(this.transfile, "");
81         File.write(dout, "");
82         File.write(allfile, "");
83         for(var i=0; i < files.length; i++)  {
84             
85             print("reading " +files[i] );
86             if (!File.exists(files[i])) {
87                 print("SKIP (does not exist) " + files[i]);
88                 continue;
89             }
90            
91             
92             File.append(dout, File.read(files[i]));
93             // it's a good idea to check with 0 compression to see if the code can parse!!
94             
95             // debug file..
96             //File.append(dout, str +"\n"); 
97             
98        
99             
100             var minfile = bpath + '/' +files[i].substr(spath.length+1).replace(/\//g, '.');
101             var transfile = bpath + '/' +files[i].substr(spath.length+1).replace(/\//g, '.') +'.lang';        
102             // let's see if we have a min file already?
103             if (true && File.exists(minfile)) {
104                 var mt = File.mtime(minfile);
105                 var ot = File.mtime(files[i]);
106                 print("compare : " + mt + "=>" + ot);
107                 if (mt >= ot) {
108                     continue;
109                     /*
110                     // then the min'files time is > than original..
111                     var str = File.read(minfile);
112                     print("using MIN FILE  "+ minfile);
113                     if (str.length) {
114                         File.append(outpath, str + "\n");
115                     }
116                     
117                     continue;
118                     */
119                 }
120                 
121             }
122             
123             print("COMPRESSING ");
124             //var codeComp = pack(str, 10, 0, 0);
125             var str = File.read(files[i]);
126             var str = this.pack(str, files[i], minfile);
127             if (str.length) {
128                 File.write(minfile, str);   
129             }
130             
131              
132             
133             //var str = File.read(minfile);
134             //print("using MIN FILE  "+ minfile);
135             //File.append(outpath, str + "\n");
136             //this.timerPrint("Wrote Files");
137             /*
138             if (codeComp.length) {
139                 //print(codeComp);
140                 
141                 File.append(outpath, codeComp+"\n");
142                 File.write(minfile, codeComp);
143             }
144             */
145             //print(codeComp);
146            // if (i > 10) return;
147         }  
148         if (this.translate) {
149             
150                
151             print("MERGING LANGUAGE");
152             File.write(outpath, "if (typeof(_T) == 'undefined') { _T={};}\n");
153             
154             var transfileAll =  bpath + '/_translation_.js';
155             File.write(transfileAll, "");
156             for(var i=0; i < files.length; i++)  {
157                 var transfile= bpath + '/' +files[i].substr(spath.length+1).replace(/\//g, '.') +'.lang.trans';
158                 var transmd5 = bpath + '/' +files[i].substr(spath.length+1).replace(/\//g, '.') +'.lang';
159                 if (File.exists(transmd5)) {
160                     var str = File.read(transmd5);
161                     if (str.length) {
162                         File.append(outpath, str + "\n");
163                     }
164                 }
165                 if (File.exists(transfile)) {
166                     var str = File.read(transfile);
167                     if (str.length) {
168                         File.append(transfileAll, str);
169                     }
170                 }
171                 
172                
173             }
174         }
175         print("MERGING SOURCE");
176         
177         for(var i=0; i < files.length; i++)  {
178          
179             var minfile = bpath + '/' +files[i].substr(spath.length+1).replace(/\//g, '.');
180             if (!File.exists(minfile)) {
181                 continue;
182             }
183             var str = File.read(minfile);
184             print("using MIN FILE  "+ minfile);
185             if (str.length) {
186                 File.append(outpath, str + "\n");
187             }
188         }
189         
190         
191         //File.append(dout, "\n");// end the function 
192         
193     
194     
195     },
196     /**
197      * Core packing routine  for a file
198      * 
199      * @param str - str source text..
200      * @param fn - filename (for reference?)
201      * @param minfile - min file location...
202      * 
203      */
204     
205     pack : function (str,fn,minfile)
206     {
207     
208         var tr = new  TokenReader();
209         this.timerPrint("START" + fn);
210         
211         // we can load translation map here...
212         
213         var toks = tr.tokenize(str,false); // dont merge xxx + . + yyyy etc.
214         
215         // at this point we can write a language file...
216         if (this.translate) {
217             this.writeTranslateFile(fn, minfile, tr.translateMap);
218         }
219         
220         this.activeFile = fn;
221         
222         // and replace if we are generating a different language..
223         
224         
225         
226         
227         this.timerPrint("Tokenized");
228         //return;//
229         var sp = new JSDOC.ScopeParser(new JSDOC.TokenStream(toks, str.length));
230         this.timerPrint("Converted to Parser");
231         sp.packer = this;
232         sp.buildSymbolTree();
233         this.timerPrint("Built Sym tree");
234         sp.mungeSymboltree();
235         this.timerPrint("Munged Sym tree");
236         print(sp.warnings.join("\n"));
237         var out = JSDOC.CompressWhite(sp.ts, this);
238         this.timerPrint("Compressed");
239         return out;
240         
241     },
242     
243     timerPrint: function (str) {
244         var ntime = new Date() * 1;
245         var tdif =  ntime -this.timer;
246         this.timer = ntime;
247         print('['+tdif+']'+str);
248     },
249     
250     /**
251      * 
252      * Translation concept...
253      * -> replace text strings with _T....
254      * -> this file will need inserting at the start of the application....
255      * -> we need to generate 2 files, 
256      * -> a reference used to do the translation, and the _T file..
257      * 
258      */
259     
260     writeTranslateFile : function(fn, minfile, map) 
261     {
262         var transfile = minfile + '.lang.trans';
263         var transmd5 = minfile + '.lang';
264         var i = 0;
265         var v = '';
266         if (File.exists(transfile)) {
267             File.remove(transfile);
268         }
269         if (File.exists(transmd5)) {
270             File.remove(transmd5);
271         }
272         for(v in map) { i++; break };
273         if (!i ) {
274             return; // no strings in file...
275         }
276         var ff = fn.split('/');
277         var ffn = ff[ff.length-1];
278          
279          
280         File.write(transfile, "\n" + ffn.toSource() + " : {");
281         var l = '';
282         var _tout = {}
283          
284          File.write(transmd5, '');
285         for(v in map) {
286             File.append(transfile, l + "\n\t \"" + v + '" : "' + v + '"');
287             l = ',';
288             // strings are raw... - as the where encoded to start with!!!
289             File.append(transmd5, '_T[' + (ffn + '-' + v).md5().toSource() + ']="'+v+"\";\n");
290         }
291         File.append(transfile, "\n},"); // always one trailing..
292         
293          
294     },
295     stringHandler : function(tok)
296     {
297         //print("STRING HANDLER");
298        // callback when outputing compressed file, 
299         if (!this.translate) {
300          //   print("TURNED OFF");
301             return tok.outData;
302         }
303         if (tok.qc != '"') {
304             return tok.outData;
305         }
306         var sval = tok.data.substring(1,tok.data.length-1);
307         // blank with tabs or spaces..
308         //if (!sval.replace(new RegExp("(\\\\n|\\\\t| )+",'g'), '').length) {
309        //     return tok.outData;
310        // }
311         
312         
313         
314         
315         var ff = this.activeFile.split('/');
316         var ffn = ff[ff.length-1];
317         return '_T[' + (ffn + '-' + sval).md5().toSource() + ']';
318         
319         
320     }
321     
322     
323 });