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