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