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