JSDOC/SymbolSet.js
[gnome.introspection-doc-generator] / JSDOC / SymbolSet.js
1 //<script type="text/javascript">
2
3  
4 XObject         = imports.XObject.XObject;
5 DocComment      = imports.DocComment.DocComment;
6 // circular references..
7 ///Options         = imports.BuildDocs.Options;
8 //Parser          = imports.Parser.Parser;
9 //Symbol          = imports.Symbol.Symbol;
10
11
12
13 SymbolSet = XObject.define(
14     function() {
15         this.init();
16     },
17     Object,
18     {
19         
20         _index : false,
21         
22         
23         init : function() {
24             this._index = {};
25         },
26
27         keys : function() 
28         {
29             var found = [];
30             for (var p in this._index) {
31                 found.push(p);
32             }
33             return found;
34         },
35
36
37         hasSymbol : function(alias) {
38             return typeof(this._index[alias]) != 'undefined';
39             //return this.keys().indexOf(alias) > -1;
40         },
41
42         addSymbol : function(symbol) {
43             //print("ADDING SYMBOL:"+symbol.alias.toString());
44             if (!symbol.is) {
45                 print ("FAILED TO UNSERIALIZE?" );
46                 Seed.quit();
47             }
48             
49             if (this.hasSymbol(symbol.alias)) {
50                 imports.BuildDocs.Options.LOG.warn("Overwriting symbol documentation for: "+symbol.alias + ".");
51             }
52             this._index[symbol.alias] = symbol;
53         },
54
55         getSymbol : function(alias) {
56             
57             if (this.hasSymbol(alias)) return this._index[alias];
58             return false;
59         },
60
61         toArray : function() {
62             var found = [];
63             for (var p in this._index) {
64                 found.push(this._index[p]);
65             }
66             return found;
67         },
68         /**
69          * for serializing
70          */
71         toJSON : function() {
72             return {
73                 '*object' : 'SymbolSet',
74                 _index : this._index
75             };
76             
77         },
78
79
80         deleteSymbol : function(alias) {
81             if (!this.hasSymbol(alias)) return;
82             delete this._index[alias];
83         },
84
85         renameSymbol : function(oldName, newName) {
86             // todo: should check if oldname or newname already exist
87             if (typeof(this._index[oldName]) == "undefined") {
88                 throw "Cant rename " + oldName + " to " + newName + " As it doesnt exist";
89                }
90             this._index[newName] = this._index[oldName];
91             this.deleteSymbol(oldName);
92             this._index[newName].alias = newName;
93             return newName;
94         },
95
96         relate : function() {
97             this.resolveBorrows();
98             this.resolveMemberOf();
99             this.resolveAugments();
100         },
101
102         resolveBorrows : function() {
103             for (p in this._index) {
104                 var symbol = this._index[p];
105                 
106                 if (!symbol.is) {
107                     continue;
108                     print("PROBLEM : " + p);
109                     print(JSON.stringify(symbol, null, 4));
110                    }
111                 
112                 if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
113                 
114                 var borrows = symbol.inherits;
115                 for (var i = 0; i < borrows.length; i++) {
116                     var borrowed = this.getSymbol(borrows[i].alias);
117                     if (!borrowed) {
118                         imports.BuildDocs.Options.LOG.warn("Can't borrow undocumented "+borrows[i].alias+".");
119                         continue;
120                     }
121                     
122                     var borrowAsName = borrows[i].as;
123                     var borrowAsAlias = borrowAsName;
124                     if (!borrowAsName) {
125                         imports.BuildDocs.Options.LOG.warn("Malformed @borrow, 'as' is required.");
126                         continue;
127                     }
128                     
129                     if (borrowAsName.length > symbol.alias.length && borrowAsName.indexOf(symbol.alias) == 0) {
130                         borrowAsName = borrowAsName.replace(borrowed.alias, "")
131                     }
132                     else {
133                         var joiner = "";
134                         if (borrowAsName.charAt(0) != "#") joiner = ".";
135                         borrowAsAlias = borrowed.alias + joiner + borrowAsName;
136                     }
137                     
138                     borrowAsName = borrowAsName.replace(/^[#.]/, "");
139                             
140                     if (this.hasSymbol(borrowAsAlias)) continue;
141
142                     var clone = borrowed.clone();
143                     clone.name = borrowAsName;
144                     clone.alias = borrowAsAlias;
145                     this.addSymbol(clone);
146                 }
147             }
148         },
149
150         resolveMemberOf : function() {
151             for (var p in this._index) {
152                 var symbol = this.getSymbol(p);
153                 if (!symbol.is) {
154                     continue;
155                     print("PROBLEM : " + p);
156                     print(JSON.stringify(symbol, null, 4));
157                    }
158                 if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
159                 
160                 // the memberOf value was provided in the @memberOf tag
161                 else if (symbol.memberOf) {
162                     var parts = symbol.alias.match(new RegExp("^("+symbol.memberOf+"[.#-])(.+)$"));
163                     
164                     // like foo.bar is a memberOf foo
165                     if (parts) {
166                         symbol.memberOf = parts[1];
167                         symbol.name = parts[2];
168                     }
169                     // like bar is a memberOf foo
170                     else {
171                         var joiner = symbol.memberOf.charAt(symbol.memberOf.length-1);
172                         if (!/[.#-]/.test(joiner)) symbol.memberOf += ".";
173                         
174                         this.renameSymbol(p, symbol.memberOf + symbol.name);
175                     }
176                 }
177                 // the memberOf must be calculated
178                 else {
179                     var parts = symbol.alias.match(/^(.*[.#-])([^.#-]+)$/);
180                     if (parts) {
181                         symbol.memberOf = parts[1];
182                         symbol.name = parts[2];                         
183                     }
184                 }
185
186                 // set isStatic, isInner
187                 if (symbol.memberOf) {
188                     switch (symbol.memberOf.charAt(symbol.memberOf.length-1)) {
189                         case '#' :
190                             symbol.isStatic = false;
191                             symbol.isInner = false;
192                             break;
193                             
194                         case '.' :
195                             symbol.isStatic = true;
196                             symbol.isInner = false;
197                             break;
198                             
199                         case '-' :
200                             symbol.isStatic = false;
201                             symbol.isInner = true;
202                             break;
203                             
204                     }
205                 }
206                 
207                 // unowned methods and fields belong to the global object
208                 if (!symbol.is("CONSTRUCTOR") && !symbol.isNamespace && symbol.memberOf == "") {
209                     symbol.memberOf = "_global_";
210                 }
211                 
212                 // clean up
213                 if (symbol.memberOf.match(/[.#-]$/)) {
214                     symbol.memberOf = symbol.memberOf.substr(0, symbol.memberOf.length-1);
215                 }
216                 //print("looking for memberOf: " + symbol.memberOf + " FOR " + symbol.alias);
217                 // add to parent's methods or properties list
218                 if (symbol.memberOf) {
219                     var container = this.getSymbol(symbol.memberOf);
220                     if (!container) {
221                         if (SymbolSet.isBuiltin(symbol.memberOf)) {
222                             container = imports.Parser.Parser.addBuiltin(symbol.memberOf);
223                         }
224                         else {
225                            // print("symbol NOT a BUILT IN - createing a container");
226                             // Eg. Ext.y.z (missing y)
227                             // we need to add in the missing symbol...
228                             container = new imports.Symbol.Symbol(symbol.memberOf, [], "OBJECT", new DocComment(""));
229                             container.isNamespace = true;
230                             this.addSymbol( container );
231                            // print(container.toSource());
232                             //container = this.getSymbol(symbol.memberOf);
233                             // fake container ... so dont ad symbols to it..
234                             continue;
235                             container = false;
236                             //LOG.warn("Can't document "+symbol.name +" as a member of undocumented symbol "+symbol.memberOf+".");
237                             //LOG.warn("We only have the following symbols: \n" + 
238                             //    this.keys.toSource());
239                         }
240                     }
241                     
242                     if (container && !container.isNamespace) container.addMember(symbol);
243                 }
244             }
245         },
246
247         resolveAugments : function() {
248             // does this sort out multiple extends???
249             for (var p in this._index) 
250             {
251                 var symbol = this.getSymbol(p);
252                 if (!symbol.is) {
253                     continue;
254                     print("PROBLEM : " + p);
255                     print(JSON.stringify(symbol, null, 4));
256                 }
257                 
258                 
259                 this.buildAugmentsList(symbol); /// build heirachy of inheritance...
260                 if (symbol.alias == "_global_" || symbol.is("FILE")) continue;
261                 
262                 var augments = symbol.augments;
263                 for(var ii = 0, il = augments.length; ii < il; ii++) {
264                     var contributer = this.getSymbol(augments[ii]);
265                     
266                     
267                     
268                     if (contributer) {
269                         contributer.childClasses.push(symbol.alias);
270                         symbol.inheritsFrom.push(contributer.alias);
271                         //if (!isUnique(symbol.inheritsFrom)) {
272                         //    imports.BuildDocs.Options.LOG.warn("Can't resolve augments: Circular reference: "+symbol.alias+" inherits from "+contributer.alias+" more than once.");
273                         //}
274                         //else {
275                             var cmethods = contributer.methods;
276                             var cproperties = contributer.properties;
277                             var cfgs = contributer.cfgs;
278                             for (var ci = 0, cl = cmethods.length; ci < cl; ci++) {   
279                                 symbol.inherit(cmethods[ci]);
280                             }
281                             for (var ci = 0, cl = cproperties.length; ci < cl; ci++) {
282                                 symbol.inherit(cproperties[ci]);
283                             }
284                             for (var ci in cfgs) {
285                                 symbol.addConfig(cfgs[ci]);
286                             }
287                             
288                                 
289                         //}
290                     }
291                     else {
292                         
293                         imports.BuildDocs.Options.LOG.warn("Can't augment contributer: '"+augments[ii]+"', not found. FOR: " + symbol.alias);
294                         
295                         //LOG.warn("We only have the following symbols: \n" + 
296                           //      this.keys().toSource().split(",").join(",    \n"));
297                        }
298
299                 }
300             }
301         },
302
303         buildAugmentsList : function(symbol)
304         {
305             // basic idea is to add all the child extends to the parent.. without looping forever..
306             
307             if (!symbol.augments.length) {
308                 return;
309             }
310             
311             var _t = this;
312             print("buildAugmentsList:" + symbol.alias);
313             var addAugments = function (alist, forceit) { // returns number added..
314                 if (!alist.length) {
315                     return 0;
316                 }
317                 print("buildAugmentsList:addAugments" + alist.length);
318                 var rval = 0;
319                 for(var ii = 0; ii < alist.length; ii++) {
320                     print("getAlias:" + alist[ii]);
321                     if (alist[ii] == symbol.alias) {
322                         continue;
323                     }
324                     var contributer = _t.getSymbol(alist[ii]);
325                     if (!contributer) {
326                         continue;
327                     }
328                     
329                     if (!forceit && symbol.augments.indexOf(alist[ii]) > -1) {
330                         continue;
331                     }
332                     if (symbol.augments.indexOf(alist[ii]) < 0) {
333                         symbol.augments.push(alist[ii]);
334                     }
335                         
336                     
337                     addAugments(contributer.augments,false);
338                     
339                     rval++;
340                 }
341                 print("buildAugmentsList: ADDED:" + rval);
342                 return rval;
343             }
344             addAugments(symbol.augments, true);
345             //while(addAugments(symbol.augments) >  0) { }
346             
347         }
348          
349 })
350
351 SymbolSet.isBuiltin = function(name) {
352     return (SymbolSet.isBuiltin.coreObjects.indexOf(name) > -1);
353 }
354 SymbolSet.isBuiltin .coreObjects = [
355     '_global_', 'Array', 'Boolean', 'Date', 'Function', 
356     'Math', 'Number', 'Object', 'RegExp', 'String'
357 ];