I'm currently writing an app in Object Oriented JavaScript, and I have a method which adds various functions on runtime to a function's prototype chain. The problem with this, is that when I try to use them in WebStorm i get an JSUnresolvedFunction error.
I've tried adding JSDoc to my code in the constructor and in the code itself but it still wont recognize the methods. Here is my code:
/**
* Example class
* #constructor
*
* #member {Function} OnConnect <-- Doesn't work
* #var {Function} OnConnect <-- Doesn't work either
* #typedef {Function} OnConnect <-- You get the deal
* #property {Function} OnConnect <-- Same for this
*/
function MyClass()
{
// Add methods dynamically
this.addMethods(["OnConnect", "OnDisconnect"]);
// Add callback listener to 'OnConnect'
// This is where WebStorm doesn't recognize my methods
this.OnConnect(function() {
console.log('Callback fired!');
});
}
/**
* Add methods which do the same thing to the class
* #param {Array} methods
* #returns {void}
*/
MyClass.prototype.addMethods = function(methods)
{
for (var i in methods) {
this[methods[i]] = function(callback) {
/** Tons of re-used logic here */
}
}
}
just remove everything except the #property
/**
* Example class
* #constructor
*
* #property {Function} OnConnect
*/
function MyClass()
{
// Add methods dynamically
this.addMethods(["OnConnect", "OnDisconnect"]);
// Add callback listener to 'OnConnect'
// This is where WebStorm doesn't recognize my methods
this.OnConnect(function() {
console.log('Callback fired!');
});
}
/**
* Add methods which do the same thing to the class
* #param {Array} methods
* #returns {void}
*/
MyClass.prototype.addMethods = function(methods)
{
for (var i in methods) {
this[methods[i]] = function(callback) {
/** Tons of re-used logic here */
}
}
}
Related
I have a function factory:
function factory(events) {
for(const key in events) {
const { before, after } = events[key]
}
}
Where the argument events is typically:
{
only: {
before(){}
after(){}
},
except: {
before(){}
after(){}
},
}
Where the keys only, except can be anything but the values are always (must be) of type {before, after} where both before, after are functions.
How do I document this structure for events argument in my factory function using JSDoc?
The only solution I can think of is to make events an array, then I can use typedef like this:
/**
* #typedef event
* #property {function} before
* #property {function} after
*/
/**
* #typedef eventTuple
* #property {string} key
* #property {event} event
*/
/**
* #param {[eventTuple]} events
*/
function factory(events) {
for(const { key, event } of events) {
const { before, after } = event
}
}
But I really wanna keep the original structure.
Is it possible to document this event type definition in my original structure?
I'm mainly concerned about it working in VSCode which lifts these type definitions from JSDoc.
You can use TS syntax.
p.s. honestly, I'm not sure if this works everywhere. But it works for intellisense at least
/**
* #typedef event
* #property {function} before
* #property {function} after
*/
/**
* #param {{[key: string]: event}} events
*/
function factory(events) {
for (const key in events) {
const { before, after } = events[key]
}
}
I defined a #callback that way :
/**
* #callback MyClass~Handler
* #param {string} target
* #param {Options} options - Original options
*/
I use it to define my class prototype :
/**
* #param {string} name - The name
* #param {MyClass~Handler} handler
* #private
*/
MyClass.prototype._builder = function(name, handler) { //...
But how to tell JSDoc that the following function has the same definition as my MyClass~Handler (something that would be like #isacallback in the following code)?
/**
* Default handler
* #isacallback {MyClass-Handler}
* #private
*/
MyClass.prototype._defaultHandler = function(target, options) { // ...
I haven't tested this, but since #callback just defines a type, couldn't you use the #type declaration?
In other words:
/**
* Default handler
* #type {MyClass-Handler}
* #private
*/
MyClass.prototype._defaultHandler = function(target, options) { // ...
See http://usejsdoc.org/tags-type.html for further info on #type.
I have this class
/**
* #constructor
* #param {...*} var_args
*/
var Map = function(var_args) {
// insert all pairs of parameters as objects in the map
};
/**
* #constructor
* #extends {Map}
* #param {...*} var_args
*/
var ExtendedMap = function(var_args) {
goog.base(this, var_args); //<-- this obviously doesn't work!
};
goog.inherits(ExtendedMap, Map);
The problem araises given that ExtendedMap needs to extend a class (Map) which in it's constructor already has a var_args. How do I add my own constructor without messing up with the parent's constructor? I'm using the google-closure compiler.
You don't need to use goog.base, it is just a method to make things easier. In this case you would call the Map's constructor directly and using apply instead of call:
/**
* #constructor
* #extends {Map}
* #param {...*} var_args
*/
var ExtendedMap = function(var_args) {
Map.apply(this, arguments);
};
goog.inherits(ExtendedMap, Map);
I am trying to automate a particular module in our JS library and am stuck at a point where I want to define a set of properties (lets say an object that goes as construction parameter of a class).
/**
* This function initiates world peace!
* #constructor
* #param {object} defaults - The options to initiate peace.
* #param {number} defaults.issues - The number of issues being taken up.
* #param {string} defaults.source - The name of the location where process starts.
*/
var WorldPeace = function (defaults) {
// code here
};
It is well and good had all properties of the construction was defined at one location. Unfortunately, my code has a number of modules contributing to that construction properties. Lets say, at some other portion of the code (in a later file) causes to have a couple of more properties
* #param {Date} defaults.start - The date when the process started.
* #param {Date} defaults.stop - The date when the process should stop.
How do I go about adding to the original set of properties that I had previously defined for WorldPeace function? Doing something like a mixin or subclassing the properties would be going overboard! As such, if I can simply inject to a property list definition it would be great.
The easiest method is to use a record type:
/**
* This function initiates world peace!
* #constructor
* #param {{issues: number, source: string}} defaults - options to initiate peace.
*/
var WorldPeace = function (defaults) {
// code here
};
You could also implement an interface:
/** #interface */
var WordPeaceDefaults;
/** #type {number} */
WorldPeaceDefaults.prototype.issues;
/** #type {string} */
WorldPeaceDefaults.prototype.source;
/**
* This function initiates world peace!
* #constructor
* #param {WorldPeaceDefaults} defaults - options to initiate peace.
*/
var WorldPeace = function (defaults) {
// code here
};
/**
* #constructor
* #implements {WorldPeaceDefaults}
*/
function MyWorldPeaceDefaults() {}
/** #type {number} */
MyWorldPeaceDefaults.prototype.issues = 0;
/** #type {string} */
MyWorldPeaceDefaults.prototype.source = '';
WordPeace(new MyWorldPeaceDefaults);
Another way to do it would be to use a typedef:
/**
* #typedef {{
* issues: number,
* source: string
* }}
*/
var WorldPeaceOptions;
/**
* #constructor
* #param {WorldPeaceOptions} defaults
*/
var WorldPeace = function (defaults) {
// code here
};
So I have several object definitions that work like this:
(function () {
var parent= constructors.Parent.prototype;
/**
* Creates an instance of Child.
*
* #constructor
* #augments Parent
* #this {Child}
* #param {object} settings
*/
var Child= function(settings) {
constructors.Parent.apply(this, arguments); //calling parent constructor
//constructor code
}
Child.prototype= new constructors.Parent();
/**
* Method1
*
* #this {Child}
* #param {string} param1
* #param {number} param2
*/
Child.prototype.method1= function(param1, param2) {
parent.method1.apply(this,arguments); //calls "super"
//method code
}
constructors.Child= Child;
}());
I do all this so that only global variable is 'constructors' and so that I don't have to say 'construtors.Child' all the time. But JSDoc3 is ignoring my comments and generates nothing on this code. Anyone knows any special tags to fix this? I don't mind if the JSDoc shows my class name as 'Child' or 'constructors.Child', either way is fine.
use #public in front of #class/#module/#namespace
see https://github.com/jsdoc3/jsdoc/issues/442
I'm not sure if this is the right way to do it, but it worked:
On another file I now have the following:
/**
* #module constructors
*/
constructors= {}
And in the file mentioned before I now have:
/**
* #exports constructors
*/
(function () {
var parent= constructors.Parent.prototype;
/**
* Creates an instance of Child.
*
* #constructor
* #augments Parent
* #this {Child}
* #param {object} settings
*/
var Child= function(settings) {
constructors.Parent.apply(this, arguments); //calling parent constructor
//constructor code
}
Child.prototype= new constructors.Parent();
/**
* Method1
*
* #this {Child}
* #param {string} param1
* #param {number} param2
*/
Child.prototype.method1= function(param1, param2) {
parent.method1.apply(this,arguments); //calls "super"
//method code
}
constructors.Child= Child;
}());