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