javascript - how - ¿Cómo documentar un módulo Require.js(AMD) con jsdoc 3 o jsdoc?
jsdoc npm (5)
Tengo 2 tipos de módulos:
Require.js Archivo principal :
require.config({
baseUrl: "/another/path",
paths: {
"some": "some/v1.0"
},
waitSeconds: 15,
locale: "fr-fr"
});
require( ["some/module", "my/module", "a.js", "b.js"],
function(someModule, myModule) {
}
);
Patrón de mediador:
define([], function(Mediator){
var channels = {};
if (!Mediator) Mediator = {};
Mediator.subscribe = function (channel, subscription) {
if (!channels[channel]) channels[channel] = [];
channels[channel].push(subscription);
};
Mediator.publish = function (channel) {
if (!channels[channel]) return;
var args = [].slice.call(arguments, 1);
for (var i = 0, l = channels[channel].length; i < l; i++) {
channels[channel][i].apply(this, args);
}
};
return Mediator;
});
¿Cómo puedo documentar esto con jsdoc3 cuando sea posible con jsdoc también?
Mis clases de AMD usan una forma ligeramente diferente, pero JSDoc tampoco las estaba documentando, así que pensé en compartir lo que funcionó para mí.
Los constructores en el espacio de nombres global se agregan automáticamente:
/**
* @classdesc This class will be documented automatically because it is not in
* another function.
* @constructor
*/
function TestClassGlobal() {
/**
* This is a public method and will be documented automatically.
*/
this.publicMethod = function() {
};
}
Si desea este comportamiento en un constructor dentro de un módulo AMD, declare como global o como miembro de un espacio de nombres :
define([], function() {
/**
* @classdesc This won''t be automatically documented unless you add memberof,
* because it''s inside another function.
* @constructor
* @memberof Namespace
*/
function TestClassNamespace() {
}
/**
* @classdesc This won''t be automatically documented unless you add global,
* because it''s inside another function.
* @constructor
* @global
*/
function TestClassForcedGlobal() {
}
});
Parece que a jsDoc no le gustan las llamadas "definir" y "requerir".
Entonces, terminamos usando varias etiquetas para hacer que la herramienta jsDoc recoja el constructor y otros métodos de clase específicos. Por favor, eche un vistazo al siguiente ejemplo: Acabo de copiar y pegar mi código fuente y lo reemplacé con su nombre de clase y nombre de método. Espero que funcione para ti.
define([], function(Mediator){
/**
* Mediator class
* This is the interface class for user related modules
* @name Mediator
* @class Mediator
* @constructor
* @return Session Object
*/
var channels = {};
if (!Mediator) Mediator = {};
/**
* .... description goes here ...
* @name Mediator#subscribe
* @function
*
* @param {Number} channel .....
* @param {String} subscription ..............
* @example
* add the sample code here if relevent.
*
*/
Mediator.subscribe = function (channel, subscription) {
if (!channels[channel]) channels[channel] = [];
channels[channel].push(subscription);
};
Mediator.publish = function (channel) {
if (!channels[channel]) return;
var args = [].slice.call(arguments, 1);
for (var i = 0, l = channels[channel].length; i < l; i++) {
channels[channel][i].apply(this, args);
}
};
return Mediator;
});
Nota: El método anterior para documentar el código JS funcionó bien para nosotros al usar jsDoc. No tengo la oportunidad de probar jsDoc3.
Parece que las cosas se han vuelto mucho más simples en JSDoc3. Lo siguiente me funcionó:
Mediador como modulo
/**
* Mediator Module
* @module Package/Mediator
*/
define([], function(Mediator){
var channels = {};
if (!Mediator) Mediator = {};
/**
* Subscribe
* @param {String} channel Channel to listen to
* @param {Function} subscription Callback when channel updates
* @memberOf module:Package/Mediator
*/
Mediator.subscribe = function (channel, subscription) {
if (!channels[channel]) channels[channel] = [];
channels[channel].push(subscription);
};
/**
* Publish
* @param {String} channel Channel that has new content
* @memberOf module:Package/Mediator
*/
Mediator.publish = function (channel) {
if (!channels[channel]) return;
var args = [].slice.call(arguments, 1);
for (var i = 0, l = channels[channel].length; i < l; i++) {
channels[channel][i].apply(this, args);
}
};
return Mediator;
});
Sin embargo, probablemente haría el siguiente cambio en el código:
/**
* Mediator Module
* @module Package/Mediator
*/
define([], function(){
var channels = {};
var Mediator = {}
...
La razón es que el módulo dice que define el Mediator
, pero parece que se toma prestado de alguna otra instancia del Mediator
. No estoy seguro de entender eso. En esta versión, está claro que el Mediator
está definido por este archivo y exportado.
Tomando el enlace de la respuesta de Muxa , vemos que la documentación se refiere específicamente a RequireJS:
La biblioteca RequireJS proporciona un método de definición que le permite escribir una función para devolver un objeto de módulo. Use la etiqueta @exports para documentar que todos los miembros de un objeto literal deben documentarse como miembros de un módulo.
Ejemplo de módulo
define(''my/shirt'', function () {
/**
* A module representing a shirt.
* @exports my/shirt
* @version 1.0
*/
var shirt = {
/** A property of the module. */
color: "black",
/** @constructor */
Turtleneck: function(size) {
/** A property of the class. */
this.size = size;
}
};
return shirt;
});
Entonces, en el ejemplo anterior, vemos que jsdoc analizará un módulo my/shirt
y lo documentará teniendo dos miembros: un color
propiedad y también una clase de Turtleneck
. También se documentará que la clase de Turtleneck
tiene su propio size
propiedad.
Ejemplo de módulo constructor
Use la etiqueta @alias para simplificar la documentación de un módulo-constructor en RequireJS.
/**
* A module representing a jacket.
* @module jacket
*/
define(''jacket'', function () {
/**
* @constructor
* @alias module:jacket
*/
var exports = function() {
}
/** Open and close your Jacket. */
exports.prototype.zip = function() {
}
return exports;
});
Lo anterior es lo que querría usar si está exportando una función de constructor como el módulo que se usará como una clase para instanciar objetos. Para resumir, no estoy seguro de usar los @lends
y otras etiquetas / técnicas que se hayan recomendado. En su lugar, intentaría seguir con las @module
, @exports
y @alias
utilizadas en la documentación que hace referencia a RequireJS .
No estoy seguro de cómo debe documentar el archivo principal de su requirejs. Si entiendo correctamente, no está realmente definiendo ningún módulo allí, sino que está ejecutando una función única que depende de varios módulos.
Esta es mi primera respuesta en SO, por favor hágame saber cómo puedo mejorar las respuestas futuras.
Tu ejemplo especifico
He estado buscando una respuesta para esto durante dos días, y parece que no hay una manera de documentar los módulos de RequireJS AMD automáticamente sin cierta redundancia (como nombres de funciones repetidos). La respuesta de Karthrik hace un buen trabajo al generar la documentación, pero si algo se cambia de nombre en el código, la documentación seguirá generándose a partir de lo que está en las etiquetas jsDoc.
Lo que terminé haciendo es lo siguiente, que se ajusta a partir del ejemplo de Karthik. Tenga en cuenta la etiqueta @lends
en la línea 1 y la eliminación de la etiqueta @name
de los bloques de comentarios jsDoc.
define([], /** @lends Mediator */ function(Mediator){
/**
* Mediator class
* This is the interface class for user related modules
* @class Mediator
*/
var channels = {};
if (!Mediator) Mediator = {};
/**
* .... description goes here ...
* @function
*
* @param {Number} channel .....
* @param {String} subscription ..............
* @example
* add the sample code here if relevent.
*
*/
Mediator.subscribe = function (channel, subscription) {
if (!channels[channel]) channels[channel] = [];
channels[channel].push(subscription);
};
Mediator.publish = function (channel) {
if (!channels[channel]) return;
var args = [].slice.call(arguments, 1);
for (var i = 0, l = channels[channel].length; i < l; i++) {
channels[channel][i].apply(this, args);
}
};
return Mediator;
});
Por lo que entiendo, la etiqueta @lends
interpretará todos los comentarios jsDoc del siguiente objeto literal como parte de la clase a la que hace referencia la etiqueta @lends
. En este caso, el siguiente objeto literal es el que comienza con la function(Mediator) {
. La etiqueta @name
se elimina para que jsDoc busque en el código fuente los nombres de funciones, etc.
Nota: He usado la etiqueta @exports
en el mismo lugar donde coloco la etiqueta @lends
. Mientras eso funciona, creará un módulo en los documentos ... y solo quería generar documentos para la clase. ¡De esta manera funciona para mí!
Referencias generales de jsdoc
- Referencia de etiquetas de jsdoc-toolkit - Gran referencia para las etiquetas en jsdoc-toolkit. Tiene un montón de ejemplos, también!
- Introducción a jsDoc de 2ality : tutorial completo basado en jsDoc-toolkit.
- Referencia de jsDoc3 : bastante incompleta, pero tiene algunos ejemplos.