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