I'm curious if the following way is a good approach to use the module.exports functionality.
And if so, what is the best way to add commentary to the code so JSDoc3 can handle it correctly.
I'm currently exporting functions as follows:
Let say we have a module1.js with the following code:
/**
* Module1 module
* #module Module1
*/
module.exports = {
// no jsdoc commentary on purpose
function1: function(param1) {
function1(param1);
},
/**
* Function2
*
* Function that will do something
* #returns {boolean} return value
*/
function2: function() {
return function2();
},
}
/**
* Function1
*
* Function that will do something
* #param param1 {string} First parameter
*/
function function1(param1){
console.log(param1);
// do something
}
/**
* Function2
*
* Function that will do something
* #returns {boolean} return value
*/
function function2() {
// do something
return true;
}
and in module2.js
/**
* Module2 module
* #module Module2
*/
// Requirements
module1 = require('./module1.js');
/**
* myFunction
*
* Function that will do something
*/
function myFunction() {
const param1 = "Parameter1";
module1.function1(param1); // call function1 from module 1
}
// just an example of function2 in module2.js
const myBoolean = module1.function2();
// more stuf
The problem with this approach is that function1 will now only be described in the jsdoc file as 'inner'(local) function, and function2will now be duplicated in the generated jsdoc file one as 'static' (the exported) and one as 'inner' (local) function.
Why this approach:
The reason for this approach is: I want no functionality in exported functions. I want other developers to easily see what functions are exported. So the real functionality is put in the local function below the exports.
The question:
Is this a correct way to use the module exports?
And is this a correct way to commentary the code? (for JSDoc3)
ps: im pretty new with NodeJS
Related
I am using VSCode as my NodeJS editor and the Preview JSDOC extension.
I wonder how I can use JSDoc with restructured imports. See the example below.
I created a module, Module A:
/**
* Some function description
* #return a string + 1234
*/
const myFuncA = (someParams) => {
return `${someParams} 1234` // or whatever
};
/**
* This is a string.
*/
const myPropB = "A string";
// ...
module.exports = {
myFuncA,
myPropB
}
In module B, I'd like to use some properties or functions from module A:
Module B:
const { myFuncA } = require('../moduleA');
const propA = myFuncA(4321);
However, when hovering over myFuncA (or when typing myFuncA(...), the description is not shown.
I'm new to JSDoc, however, their docs don't cover my specific case.
I was searching for answer for this as well, and I think the best thing for this solution is to use the #memberof module:<your-module-name> syntax.
So in Module B at the top you would add something like this
/** module MyModuleName */
const { myFuncA } = require('../moduleA');
Then in Module A you would add the #memberof module:<module-name> decorator.
/**
* Some function description
* #return a string + 1234
* #memberof module:MyModuleName
*/
const myFuncA = (someParams) => {
return `${someParams} 1234` // or whatever
};
Extra Information:
As I was looking for a solution to this problem, I had the assumption that JSDoc would resolve imports. JSDoc does not resolve imports, which makes a lot of sense. If you want a function to belong to another module, you have to let JSDocs know. Credit to this github issue thread which helped me settle on this answer.
Google Flatbuffers creates in (AMD?) module for each table that one wants. I have them all in one name space called PNTCI.
Right now, I am doing something ugly and non-intuitve to merge the name spaces together by doing successive includes to the PNTCI namespace like this:
const telem = require('../messages/Telemetry_generated').PNTCI
const PNTCI = Object.assign(telem, require('../messages/header_generated').PNTCI)
The again the reason is that the autogenerated require modules have a old fashioned format that looks like this for the Header_generated.js :
// automatically generated by the FlatBuffers compiler, do not modify
/**
* #const
* #namespace
*/
var PNTCI = PNTCI || {};
/**
* Common header for all PNTCI message payloads
*
* #constructor
*/
and the end of the file looks like this:
/**
* #param {flatbuffers.Builder} builder
* #param {flatbuffers.Offset} offset
*/
PNTCI.Header.finishHeaderBuffer = function(builder, offset) {
builder.finish(offset);
};
// Exports for Node.js and RequireJS
this.PNTCI = PNTCI;
and for Telemetry_generated.js
// automatically generated by the FlatBuffers compiler, do not modify
/**
* #const
* #namespace
*/
var PNTCI = PNTCI || {};
/**
* #constructor
*/
PNTCI.PosVector = function() {
/**
* #type {flatbuffers.ByteBuffer}
*/
this.bb = null;
and then the end of the file looks like this:
PNTCI.Telemetry.finishTelemetryBuffer = function(builder, offset) {
builder.finish(offset);
};
// Exports for Node.js and RequireJS
this.PNTCI = PNTCI;
The use of namespaces isn't idiomatic to Node.js because a module itself acts as a namespace, so the problem is specific to these particular modules.
It can be written shorter with object spread syntax:
const PNTCI = {
...require('../messages/Telemetry_generated').PNTCI,
...require('../messages/header_generated').PNTCI
};
Which is syntactic sugar for:
const PNTCI = Object.assign({},
require('../messages/Telemetry_generated').PNTCI,
require('../messages/header_generated').PNTCI
);
If these modules are constantly used together, it may be beneficial to re-export them as single module:
module.exports = {
...require('../messages/Telemetry_generated').PNTCI,
...require('../messages/header_generated').PNTCI
};
Since there's generally no need for namespaces in Node, merging modules under single PNTCI variable may be unneeded; modules could be imported separately to different variables. This makes the application more modular if only some of these modules are used in some places.
I am writing a script in SS2 and I ran into doc that stated that I should do the below. I have done this and the paths are right but it doesn't seem to see underscore as it comes back as undefined, when trying to use it. Any help with this would be great, thanks
define( [ 'N/email'
, 'N/runtime'
, 'N/search'
, '/SuiteScripts/af_scripts/underscore.js#1.8.3/underscore'
],
function( email, runtime, search, _) {
function onRequest( context ) {
var request = context.request;
var us = _;
}
return {
onRequest: onRequest
};
} );
In my case, I used lodash to add HTML file contents to my suitelet
When you define your modules you can insert the lodash library at the end just like
define(['N/file', 'N/record', 'N/search', 'N/ui/serverWidget','./lodash.js'],
but at function you should not insert anything just like
function(file, record, search, serverWidget) {
Here is a sample of code to load a file and get his contents using lodash
/**
* #NApiVersion 2.x
* #NScriptType Suitelet
* #NModuleScope SameAccount
*/
define(['N/file', 'N/record', 'N/search', 'N/ui/serverWidget','./lodash.js'],
/**
* #param {file} file
* #param {record} record
* #param {search} search
* #param {serverWidget} serverWidget
*/
function(file, record, search, serverWidget) {
/**
* Definition of the Suitelet script trigger point.
*
* #param {Object} context
* #param {ServerRequest} context.request - Encapsulation of the incoming request
* #param {ServerResponse} context.response - Encapsulation of the Suitelet response
* #Since 2015.2
*/
function onRequest(context) {
var templateFile = file.load({
id: 'filePath'
});
//for example.
var compiled = _.template(templateFile.getContents());
}
return {
onRequest: onRequest
};
});
Note:
I inserted the file to the same location as my suitelet in the file cabinet that why I used this relative path (./lodash.js), use the full path if the suitelet is not at the same file.
I have not see how to do it that way. But the way I found that works is like this:
/**
* #NApiVersion 2.x
* #NScriptType usereventscript
*/
require.config({
paths:{
"coolthing":"/SuiteScripts/myFavoriteJsLibrary"
}
});
define(['coolthing'],function (coolthing){
return {
beforeLoad:function beforeLoad(ctx){
coolthing.times(2,function(){
log.debug('log','log');
});
}
};
});
I put underscore-min.js in the same folder as my Suitescripts.
Then I created a config file named 'underscoreConfig.json' in the same folder with the following contents:
{
"paths":{
"underscore": "./underscore-min"
}
}
Then I add the following to my scripts:
/**
* #NApiVersion 2.x
* #NScriptType UserEventScript
* #NModuleScope SameAccount
* #NAmdConfig ./underscoreConfig.json
*/
define(['underscore', 'N/record', 'N/search'],
/**
* #param {underscore} underscore
* #param {record} record
* #param {search} search
*/
function(_, record, search) {
Now I am able to call Underscore functions in my scripts.
E.g.
var segmentObj = _.findWhere(segmentFields, {id: segmentId});
I'm just starting to add some JSDoc comments to a code base I've been working on, for the most part this seems to work, but there's one area that's causing me some difficulties.
If I describe a function constructor in a file, and then export it on the module.exports, when I later require() that module, I get no documentation on the type and the inferred type is set as |exports. Clicking on the doesn't take me anywhere. I currently have:
/**
* Creates an instance of the StatusCodeErrorItem
* #param {string} message The message for this error
* #param {object} params The parameters that caused this error to occur
* #alias lib/common/StatusCodeErrorItem.StatusCodeErrorItem
* #returns {StatusCodeErrorItem}
* #constructor
*/
function StatusCodeErrorItem(message, params) {
this.message = message;
this.params = params;
}
/**
* Holds information about an error
* #module lib/common/StatusCodeErrorItem
*/
module.exports = StatusCodeErrorItem;
and in the file that uses it:
var StatusCodeErrorItem = require('./StatusCodeErrorItem');
I'd thought at this point that'd I'd be able to press f1 to bring up the inline documentation, and see the definition of StatusCodeErrorItem as described in that file. But instead I only see: inferred type StatusCodeErrorItem|exports
Webstorm 9
Node.js 0.10.36 (I know both are old)
Any thoughts on what I'm doing wrong? Is what I'm after even possible? Are my versions simply too old?
Cheers
Webstorm 2016.1.1 solves the issue. The below JSDoc gets correctly assigned to types pulled in by require. I'll now be pestering people to get me a new license.
'use strict';
/**
* Creates an instance of the StatusCodeErrorItem
* #memberof common
* #constructor
* #classdesc A class for holding information about an error. The params object allows the tracking of the function
* parameters that caused the error, but should not be used to store large objects.
* #description Creates an instance of the StatusCodeErrorItem with the given message and optional params object
* #param {string} message The message for this error
* #param {object} [params] The parameters that caused this error to occur
* #returns {StatusCodeErrorItem}
* #see {#link module:lib/common/StatusCodeError.StatusCodeError|StatusCodeError}
*/
function StatusCodeErrorItem(message, params) {
this.message = message;
this.params = params;
}
/**
* Surfaces a class that holds information about an error
* #module lib/common/StatusCodeErrorItem
*/
module.exports = StatusCodeErrorItem;
Can someone please give me an example on how to use the #event tag properly.
I've looked at the jsdoc3 documentation here:
http://usejsdoc.org/tags-event.html
but I could not get it working.
I am using nodejs, and I have a module in MyClass/index.js which exports a constructor by the name of MyClass:
module.exports = MyClass;
myClass = function () { ... };
and I have tried to add
/**
* Snowball event.
* #event MyClass#snowball
*/
In the compiled docs, snowball appears in the global list of events, but when I click on it, it tells me
The requested URL /{path-to-my-docs}/MyClass.html was not found on this server.
Thanks in advance.
This works fine:
/**
* #class
*/
function Blah() {
}
/**
* #event Blah#something
* #type {Object}
* #property {integer} some_field Represents something or other.
*/