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