|
1 /** @constructor */ |
|
2 JSDOC.SymbolSet = function() { |
|
3 this.init(); |
|
4 } |
|
5 |
|
6 JSDOC.SymbolSet.prototype.init = function() { |
|
7 this._index = new Hash(); |
|
8 } |
|
9 |
|
10 JSDOC.SymbolSet.prototype.keys = function() { |
|
11 return this._index.keys(); |
|
12 } |
|
13 |
|
14 JSDOC.SymbolSet.prototype.hasSymbol = function(alias) { |
|
15 return this._index.hasKey(alias); |
|
16 } |
|
17 |
|
18 JSDOC.SymbolSet.prototype.addSymbol = function(symbol) { |
|
19 if (this.hasSymbol(symbol.alias)) { |
|
20 LOG.warn("Overwriting symbol documentation for: "+symbol.alias + "."); |
|
21 } |
|
22 this._index.set(symbol.alias, symbol); |
|
23 } |
|
24 |
|
25 JSDOC.SymbolSet.prototype.getSymbol = function(alias) { |
|
26 if (this.hasSymbol(alias)) return this._index.get(alias); |
|
27 } |
|
28 |
|
29 JSDOC.SymbolSet.prototype.getSymbolByName = function(name) { |
|
30 for (var p = this._index.first(); p; p = this._index.next()) { |
|
31 var symbol = p.value; |
|
32 if (symbol.name == name) return symbol; |
|
33 } |
|
34 } |
|
35 |
|
36 JSDOC.SymbolSet.prototype.toArray = function() { |
|
37 return this._index.values(); |
|
38 } |
|
39 |
|
40 JSDOC.SymbolSet.prototype.deleteSymbol = function(alias) { |
|
41 if (!this.hasSymbol(alias)) return; |
|
42 this._index.drop(alias); |
|
43 } |
|
44 |
|
45 JSDOC.SymbolSet.prototype.renameSymbol = function(oldName, newName) { |
|
46 // todo: should check if oldname or newname already exist |
|
47 this._index.replace(oldName, newName); |
|
48 this._index.get(newName).alias = newName; |
|
49 return newName; |
|
50 } |
|
51 |
|
52 JSDOC.SymbolSet.prototype.relate = function() { |
|
53 this.resolveBorrows(); |
|
54 this.resolveMemberOf(); |
|
55 this.resolveAugments(); |
|
56 } |
|
57 |
|
58 JSDOC.SymbolSet.prototype.resolveBorrows = function() { |
|
59 for (var p = this._index.first(); p; p = this._index.next()) { |
|
60 var symbol = p.value; |
|
61 if (symbol.is("FILE") || symbol.is("GLOBAL")) continue; |
|
62 |
|
63 var borrows = symbol.inherits; |
|
64 for (var i = 0; i < borrows.length; i++) { |
|
65 |
|
66 if (/#$/.test(borrows[i].alias)) { |
|
67 LOG.warn("Attempted to borrow entire instance of "+borrows[i].alias+" but that feature is not yet implemented."); |
|
68 return; |
|
69 } |
|
70 var borrowed = this.getSymbol(borrows[i].alias); |
|
71 |
|
72 if (!borrowed) { |
|
73 LOG.warn("Can't borrow undocumented "+borrows[i].alias+"."); |
|
74 continue; |
|
75 } |
|
76 |
|
77 if (borrows[i].as == borrowed.alias) { |
|
78 var assumedName = borrowed.name.split(/([#.-])/).pop(); |
|
79 borrows[i].as = symbol.name+RegExp.$1+assumedName; |
|
80 LOG.inform("Assuming borrowed as name is "+borrows[i].as+" but that feature is experimental."); |
|
81 } |
|
82 |
|
83 var borrowAsName = borrows[i].as; |
|
84 var borrowAsAlias = borrowAsName; |
|
85 if (!borrowAsName) { |
|
86 LOG.warn("Malformed @borrow, 'as' is required."); |
|
87 continue; |
|
88 } |
|
89 |
|
90 if (borrowAsName.length > symbol.alias.length && borrowAsName.indexOf(symbol.alias) == 0) { |
|
91 borrowAsName = borrowAsName.replace(borrowed.alias, "") |
|
92 } |
|
93 else { |
|
94 var joiner = ""; |
|
95 if (borrowAsName.charAt(0) != "#") joiner = "."; |
|
96 borrowAsAlias = borrowed.alias + joiner + borrowAsName; |
|
97 } |
|
98 |
|
99 borrowAsName = borrowAsName.replace(/^[#.]/, ""); |
|
100 |
|
101 if (this.hasSymbol(borrowAsAlias)) continue; |
|
102 |
|
103 var clone = borrowed.clone(); |
|
104 clone.name = borrowAsName; |
|
105 clone.alias = borrowAsAlias; |
|
106 this.addSymbol(clone); |
|
107 } |
|
108 } |
|
109 } |
|
110 |
|
111 JSDOC.SymbolSet.prototype.resolveMemberOf = function() { |
|
112 for (var p = this._index.first(); p; p = this._index.next()) { |
|
113 var symbol = p.value; |
|
114 if (symbol.is("FILE") || symbol.is("GLOBAL")) continue; |
|
115 |
|
116 // the memberOf value was provided in the @memberOf tag |
|
117 else if (symbol.memberOf) { |
|
118 |
|
119 // like foo.bar is a memberOf foo |
|
120 if (symbol.alias.indexOf(symbol.memberOf) == 0) { |
|
121 var memberMatch = new RegExp("^("+symbol.memberOf+")[.#-]?(.+)$"); |
|
122 var aliasParts = symbol.alias.match(memberMatch); |
|
123 |
|
124 if (aliasParts) { |
|
125 symbol.memberOf = aliasParts[1]; |
|
126 symbol.name = aliasParts[2]; |
|
127 } |
|
128 |
|
129 var nameParts = symbol.name.match(memberMatch); |
|
130 |
|
131 if (nameParts) { |
|
132 symbol.name = nameParts[2]; |
|
133 } |
|
134 } |
|
135 // like bar is a memberOf foo |
|
136 else { |
|
137 var joiner = symbol.memberOf.charAt(symbol.memberOf.length-1); |
|
138 if (!/[.#-]/.test(joiner)) symbol.memberOf += "."; |
|
139 this.renameSymbol(symbol.alias, symbol.memberOf + symbol.name); |
|
140 } |
|
141 } |
|
142 // the memberOf must be calculated |
|
143 else { |
|
144 var parts = symbol.alias.match(/^(.*[.#-])([^.#-]+)$/); |
|
145 if (parts) { |
|
146 symbol.memberOf = parts[1]; |
|
147 symbol.name = parts[2]; |
|
148 } |
|
149 } |
|
150 |
|
151 // set isStatic, isInner |
|
152 if (symbol.memberOf) { |
|
153 switch (symbol.memberOf.charAt(symbol.memberOf.length-1)) { |
|
154 case '#' : |
|
155 symbol.isStatic = false; |
|
156 symbol.isInner = false; |
|
157 break; |
|
158 case '.' : |
|
159 symbol.isStatic = true; |
|
160 symbol.isInner = false; |
|
161 break; |
|
162 case '-' : |
|
163 symbol.isStatic = false; |
|
164 symbol.isInner = true; |
|
165 break; |
|
166 default: // memberOf ends in none of the above |
|
167 symbol.isStatic = true; |
|
168 break; |
|
169 } |
|
170 } |
|
171 |
|
172 // unowned methods and fields belong to the global object |
|
173 if (!symbol.is("CONSTRUCTOR") && !symbol.isNamespace && symbol.memberOf == "") { |
|
174 symbol.memberOf = "_global_"; |
|
175 } |
|
176 |
|
177 // clean up |
|
178 if (symbol.memberOf.match(/[.#-]$/)) { |
|
179 symbol.memberOf = symbol.memberOf.substr(0, symbol.memberOf.length-1); |
|
180 } |
|
181 // add to parent's methods or properties list |
|
182 if (symbol.memberOf) { |
|
183 |
|
184 var container = this.getSymbol(symbol.memberOf); |
|
185 if (!container) { |
|
186 if (JSDOC.Lang.isBuiltin(symbol.memberOf)) container = JSDOC.Parser.addBuiltin(symbol.memberOf); |
|
187 else { |
|
188 LOG.warn("Trying to document "+symbol.name +" as a member of undocumented symbol "+symbol.memberOf+"."); |
|
189 } |
|
190 } |
|
191 |
|
192 if (container) container.addMember(symbol); |
|
193 } |
|
194 } |
|
195 } |
|
196 |
|
197 JSDOC.SymbolSet.prototype.resolveAugments = function() { |
|
198 for (var p = this._index.first(); p; p = this._index.next()) { |
|
199 var symbol = p.value; |
|
200 |
|
201 if (symbol.alias == "_global_" || symbol.is("FILE")) continue; |
|
202 JSDOC.SymbolSet.prototype.walk.apply(this, [symbol]); |
|
203 } |
|
204 } |
|
205 |
|
206 JSDOC.SymbolSet.prototype.walk = function(symbol) { |
|
207 var augments = symbol.augments; |
|
208 for(var i = 0; i < augments.length; i++) { |
|
209 var contributer = this.getSymbol(augments[i]); |
|
210 if (!contributer && JSDOC.Lang.isBuiltin(''+augments[i])) { |
|
211 contributer = new JSDOC.Symbol("_global_."+augments[i], [], augments[i], new JSDOC.DocComment("Built in.")); |
|
212 contributer.isNamespace = true; |
|
213 contributer.srcFile = ""; |
|
214 contributer.isPrivate = false; |
|
215 JSDOC.Parser.addSymbol(contributer); |
|
216 } |
|
217 |
|
218 if (contributer) { |
|
219 if (contributer.augments.length) { |
|
220 JSDOC.SymbolSet.prototype.walk.apply(this, [contributer]); |
|
221 } |
|
222 |
|
223 symbol.inheritsFrom.push(contributer.alias); |
|
224 //if (!isUnique(symbol.inheritsFrom)) { |
|
225 // LOG.warn("Can't resolve augments: Circular reference: "+symbol.alias+" inherits from "+contributer.alias+" more than once."); |
|
226 //} |
|
227 //else { |
|
228 var cmethods = contributer.methods; |
|
229 var cproperties = contributer.properties; |
|
230 |
|
231 for (var ci = 0, cl = cmethods.length; ci < cl; ci++) { |
|
232 if (!cmethods[ci].isStatic) symbol.inherit(cmethods[ci]); |
|
233 } |
|
234 for (var ci = 0, cl = cproperties.length; ci < cl; ci++) { |
|
235 if (!cproperties[ci].isStatic) symbol.inherit(cproperties[ci]); |
|
236 } |
|
237 //} |
|
238 } |
|
239 else LOG.warn("Can't augment contributer: "+augments[i]+", not found."); |
|
240 } |
|
241 } |