c4792da4af993cc5b5a70f5493f94f7b7a859807
[app.jsdoc] / JSDOC / DocTag.js
1 //<script  type="text/javascript">
2  
3  
4 XObject = imports.XObject.XObject;
5
6 Options = imports.Options.Options;
7
8  
9 /**
10  * DocTag - represents a single A=b tag.
11  * @class DocTag
12  */
13   
14  
15 DocTag = XObject.define(
16
17 /**
18  * @constructor
19  * @arg {String} src
20  */
21
22     function(src) {
23         this.title        = "";
24         this.type         = "";
25         this.name         = "";
26         this.isOptional   = false;
27         this.defaultValue = "";
28         this.desc         = "";
29         if (typeof src != "undefined") {
30             this.parse(src);
31         }
32     }, 
33     Object,
34     {
35         
36         title: '',
37         type: '',
38         name : '',
39         isOptional : false,
40         defaultValue : '',
41         desc : '',
42         /**
43          * serialize..
44          */
45         toJSON :function(t)
46         {
47             var ret = { '*object' : 'DocTag' };
48             
49             for (var i in this) {
50                 switch (typeof(this[i])) {
51                     case 'function':
52                        continue;
53                        continue;
54                         
55                     case 'string':
56                     case 'number':
57                     case 'boolean':                    
58                         ret[i] = this[i]; continue;
59                     default:
60                         print("unknown type:" + typeof(this[i]));
61                         Seed.quit();
62                    }
63             }
64             return ret;
65         },
66         
67
68
69         /**
70             Populate the properties of this from the given tag src.
71             @param {string} src
72          */
73         parse : function(src) {
74             if (typeof src != "string") throw "src must be a string not "+(typeof src);
75
76             try {
77                 src = this.nibbleTitle(src);
78                 //if (JSDOC.PluginManager) {
79                 //    JSDOC.PluginManager.run("onDocTagSynonym", this);
80                // }
81                 
82                 src = this.nibbleType(src);
83                 
84                 // only some tags are allowed to have names.
85                 if (this.title == "param" ||
86                     this.title == "property" ||
87                     this.title == "cfg") {
88                     // @config is deprecated
89                     
90                     src = this.nibbleName(src);
91                     // support @param name {Type} ...
92                     if (!this.type) {
93                         src = this.nibbleType(src);
94                     }
95                 }
96             }
97             catch(e) {
98                 if (Options.LOG) Options.LOG.warn(e);
99                 else throw e;
100             }
101             this.desc = src; // whatever is left
102             
103             // example tags need to have whitespace preserved
104             if (this.title != "example") this.desc = this.desc.trim();
105             
106             //if (JSDOC.PluginManager) {
107             //    JSDOC.PluginManager.run("onDocTag", this);
108             //}
109         },
110
111         /**
112             Automatically called when this is stringified.
113          */
114         toString : function() {
115             return this.desc;
116         },
117          
118
119         /**
120             Find and shift off the title of a tag.
121             @param {string} src
122             @return src
123          */
124         nibbleTitle : function(src) {
125             if (typeof src != "string") throw "src must be a string not "+(typeof src);
126             
127             var parts = src.match(/^\s*(\S+)(?:\s([\s\S]*))?$/);
128
129             if (parts && parts[1]) this.title = parts[1];
130             if (parts && parts[2]) src = parts[2];
131             else src = "";
132             
133             return src;
134         },
135          
136         /**
137             Find and shift off the type of a tag.
138             @requires frame/String.js
139             @param {string} src
140             @return src
141          */
142         nibbleType : function(src) 
143         {
144             if (typeof src != "string") throw "src must be a string not "+(typeof src);
145             
146             if (src.match(/^\s*\{/)) {
147                 var typeRange = this.balance(src,"{", "}");
148                 if (typeRange[1] == -1) {
149                     throw "Malformed comment tag ignored. Tag type requires an opening { and a closing }: "+src;
150                 }
151                 this.type = src.substring(typeRange[0]+1, typeRange[1]).trim();
152                 this.type = this.type.replace(/\s*,\s*/g, "|"); // multiples can be separated by , or |
153                 src = src.substring(typeRange[1]+1);
154             }
155             
156             return src;
157         },
158          
159
160         /**
161             Find and shift off the name of a tag.
162             @requires frame/String.js
163             @param {string} src
164             @return src
165          */
166         nibbleName : function(src) {
167             if (typeof src != "string") throw "src must be a string not "+(typeof src);
168             
169             src = src.trim();
170             
171             // is optional?
172             if (src.charAt(0) == "[") {
173                 var nameRange = this.balance(src,"[", "]");
174                 if (nameRange[1] == -1) {
175                     throw "Malformed comment tag ignored. Tag optional name requires an opening [ and a closing ]: "+src;
176                 }
177                 this.name = src.substring(nameRange[0]+1, nameRange[1]).trim();
178                 this.isOptional = true;
179                 
180                 src = src.substring(nameRange[1]+1);
181                 
182                 // has default value?
183                 var nameAndValue = this.name.split("=");
184                 if (nameAndValue.length) {
185                     this.name = nameAndValue.shift().trim();
186                     this.defaultValue = nameAndValue.join("=");
187                 }
188             }
189             else {
190                 var parts = src.match(/^(\S+)(?:\s([\s\S]*))?$/);
191                 if (parts) {
192                     if (parts[1]) this.name = parts[1];
193                     if (parts[2]) src = parts[2].trim();
194                     else src = "";
195                 }
196             }   
197
198             return src;
199         },
200         
201         balance : function(str, open, close) {
202             var i = 0;
203             while (str.charAt(i) != open) {
204                 if (i == str.length) return [-1, -1];
205                 i++;
206             }
207             
208             var j = i+1;
209             var balance = 1;
210             while (j < str.length) {
211                 if (str.charAt(j) == open) balance++;
212                 if (str.charAt(j) == close) balance--;
213                 if (balance == 0) break;
214                 j++;
215                 if (j == str.length) return [-1, -1];
216             }
217             
218             return [i, j];
219 }
220
221         
222         
223 });
224
225 // cached support?
226 DocTag.fromDump = function(t)
227 {
228     var ns = new DocTag();
229     for (var i in t) {
230         if (typeof(ns[i]) == "undefined") {
231             println("ERR:no default for DocTag:"+ i);
232         }
233        ns[i] = t[i];
234     }
235     return ns;
236 }