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