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