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