UNPKG

short-jsdoc

Version:

short and simple jsdoc Object Oriented syntax format and implementation

218 lines (190 loc) 7.28 kB
// @module shortjsdoc @class JsDocMaker var JsDocMaker = require('./class'); var _ = require('underscore'); var PluginContainer = require('./plugin'); //POST PROCESSING // @property {PluginContainer} beforeTypeBindingPlugins these plugins accept an object like // {node:parsed:jsdocmaker:self} and perform some modification to passed node:parsed instance. // This is done just before doing the type binding. JsDocMaker.prototype.beforeTypeBindingPlugins = new PluginContainer(); // @property {PluginContainer} afterTypeBindingPlugins these plugins accept an object like // {node:parsed:jsdocmaker:self} and perform some modification to passed node:parsed instance. // This is done just after doing the type binding. JsDocMaker.prototype.afterTypeBindingPlugins = new PluginContainer(); // @method postProccess so the data is already parsed but we want to normalize some // children like @extend and @ module to be properties of the unit instead children. // Also we enforce explicit parent reference, this is a class must reference its // parent module and a method muest reference its parent class. Also related to this // is the fullname property that will return an unique full name in the format // '$MODULE.$CLASS.$METHOD'. We assume that a module contains unique named classes and // that classes contain unique named properties and methods. JsDocMaker.prototype.postProccess = function() { var self = this; // set params and throws of constructors _(self.data.classes).each(function(c) { _(c.constructors).each(function(co) { co.params = _(co.children||[]).filter(function(child) { return child.annotation === 'param'; }); co.throws = _(co.children||[]).filter(function(child) { return child.annotation === 'throw' || child.annotation === 'throws'; }); }); }); }; //@method postProccessBinding precondion: call postProccess() first. We separated the post proccessing in two because we shouln't do JSON.stringify() after we bind types because of recursive loops. JsDocMaker.prototype.postProccessBinding = function() { if(this.literalObjectInstall) { this.literalObjectInstall(); } var self = this; _(self.data.modules).each(function(m) { self.beforeTypeBindingPlugins.execute({node: m, jsdocmaker: self}); self._postProccessBinding_methodSetup(m.functions, m, true); }); //at this points we have all our modules and classes - now we normalize extend, methods and params and also do the type binding. _(self.data.classes).each(function(c) { self.beforeTypeBindingPlugins.execute({node: c, jsdocmaker: self}); //class.extends property var extend = _(c.children||[]).find(function(child) { return child.annotation === 'extend' || child.annotation === 'extends'; }); if(!extend) // All classes must extend something { extend = c.extends = (self.bindClass(JsDocMaker.DEFAULT_CLASS, c) || {error: 'NAME_NOT_FOUND', name: JsDocMaker.DEFAULT_CLASS}); } else { c.extends = self.bindClass(extend.name, c); c.children = _(c.children).without(extend); //TODO: why we would want to do this? - remove this line } var implement = _(c.children||[]).filter(function(child) { return child.annotation === 'implement' || child.annotation === 'implements'; }) || []; if(!implement.length) // All classes must implement something { implement = c.implements = []//[(self.bindClass(JsDocMaker.DEFAULT_CLASS, c) || {error: 'NAME_NOT_FOUND', name: JsDocMaker.DEFAULT_CLASS})]; } else { c.implements = c.implements || []; _.each(implement, function(i) { c.implements.push(self.bindClass(i.name, c)); c.children = _(c.children).without(i); //TODO: why we would want to do this? - remove this line }) } //setup methods & constructors var methods = _(c.methods).clone() || {}; if(c.constructors) { for (var i = 0; i < c.constructors.length; i++) { var cname = 'constructor ' + i; methods[cname] = c.constructors[i]; //using invalid method name c.constructors[i].name = i+''; } } self._postProccessBinding_methodSetup(methods, c); //setup properties var propertySetup = function(prop) { prop.ownerClass = c.absoluteName; prop.absoluteName = c.absoluteName + JsDocMaker.ABSOLUTE_NAME_SEPARATOR + prop.name; if(self.installModifiers) { self.installModifiers(prop); } if(_(prop.type).isString()) { prop.type = self.parseTypeString(prop.type, c) || prop.type; } self.beforeTypeBindingPlugins.execute({node: prop, jsdocmaker: self}); }; _(c.properties).each(propertySetup); _(c.events).each(propertySetup); _(c.attributes).each(propertySetup); }); self.afterTypeBindingPlugins.execute({jsdocmaker: self}); }; JsDocMaker.prototype._postProccessBinding_methodSetup = function(methods, c, isFunction) { var self = this; c = c || {}; _(methods).each(function(method) { self.beforeTypeBindingPlugins.execute({node: method, jsdocmaker: self}); //method.param property var params = _(method.children||[]).filter(function(child) { child.text = JsDocMaker.stringTrim(child.text||''); return child.annotation === 'param'; }); method.params = params; var absoluteName = c.absoluteName || c.name || ''; if(!isFunction) { method.ownerClass = absoluteName; } else { method.ownerModule = absoluteName; } method.absoluteName = absoluteName + JsDocMaker.ABSOLUTE_NAME_SEPARATOR + method.name; _(method.params).each(function(param) { self.beforeTypeBindingPlugins.execute({node: param, jsdocmaker: self}); if(_(param.type).isString()) { param.typeOriginalString = param.type; param.type = self.parseTypeString(param.type, c) || param.type; } }); //method throws property var throw$ = _(method.children||[]).filter(function(child) { return child.annotation === 'throw' || child.annotation === 'throws'; }); method.throws = throw$; _(method.throws).each(function(t) { self.beforeTypeBindingPlugins.execute({node: t, jsdocmaker: self}); //because @throws doesn't have a name it breaks our simple grammar, so we merge the name with its text. t.text = (t.name ? t.name+' ' : '') + (t.text||''); if(_(t.type).isString()) { t.typeOriginalString = t.type; t.type = self.parseTypeString(t.type, c) || t.type; } }); //method.returns property var returns = _(method.children||[]).filter(function(child) { self.beforeTypeBindingPlugins.execute({node: child, jsdocmaker: self}); child.text = JsDocMaker.stringTrim(child.text||''); return child.annotation === 'returns' || child.annotation === 'return'; }); method.returns = returns.length ? returns[0] : {name:'',type:''}; //because @returns doesn't have a name it breaks our simple grammar, so we merge the name with its text. method.returns.text = (method.returns.name ? method.returns.name+' ' : '') + (method.returns.text||''); if(_(method.returns.type).isString()) { method.returns.type = self.parseTypeString(method.returns.type, c) || method.returns.type; } if(self.installModifiers) { self.installModifiers(method); } }); };