How to refer in JsDoc (VS Code / IntelliSense) to class from another file without direct import? - visual-studio-code

Problem
I use Visual Studio Code and use IntelliSense with JsDoc comments.
I have two modules with class declarations:
/**
* This is Foo class
*/
export default class Foo {
constructor() {}
}
and
/**
* This is Bar class
*/
export default class Bar {
constructor() {}
/**
* Init Bar from Foo
* #param {Foo} foo instance of Foo
* #returns {Bar}
*/
static initFromFoo(foo) {
return new Bar();
}
}
Class Bar use Foo as param for the method initFromFoo but IntelliSense doesn't understand that #param Foo is referred to class Foo and don't work properly and says that foo:any,
https://imgbbb.com/images/2019/09/24/image517c0ec9d1027ac9.png
How can I make IntelliSense work well?
What I have tried
Import ./foo into ./bar- this makes IntelliSense work well but I don't need this import I need just reference to the type definition.
Add reference to another file like in TypeScript /// <reference path="./foo"> - no effects
Create jsconfig.json file with the next content:
{
"compilerOptions": {
"target": "es6",
"allowSyntheticDefaultImports": true,
"checkJs": true
},
"exclude": [
"node_modules"
]
}
no effects too. It just highlights error Cannot find name 'Foo'.ts(2304)
P.S. It looks like IntelliSense limitation that related to ES6 modules. Because if I remove export/import from both files IntelliSense work as expected
https://i.ibb.co/CPL1gJC/image.png
https://i.ibb.co/xmXqzSk/image.png
P.S.S. Sorry for links to images my repo is too low for image posting.

It is possible to import type by import(path) statement.
For example:
/**
* Init Bar from Foo
* #param {import('./foo').default} foo instance of Foo
* #returns {Bar}
*/
static initFromFoo(foo) {
return new Bar();
}
OR
/**
* #typedef {import('./foo').default} Foo
*
* Init Bar from Foo
* #param {Foo} foo instance of Foo
* #returns {Bar}
*/
static initFromFoo(foo) {
return new Bar();
}
P.S. It is hack only for Visual Studio Code. It isn't valid JsDoc.

Related

Include function alias

I have a library, Foo/Foo.h
/**
My core library.
*/
namespace Foo {
/**
My function.
*/
void myfunc();
} // namespace Foo
And a library that uses that library, Bar/Bar.h
#include <Foo.h>
/**
Library using alias.
*/
namespace Bar {
/**
\copydoc Foo::myfunc()
*/
using Foo::myfunc;
} // namespace Bar
Now my question is simple: How do I include the documentation of Foo::myfunc in the Bar namespace?
In particular, with the Doxyfile:
INPUT = Foo Bar
doxygen 1.9.1 does not show the included function:

Doxygen documentation for enum class in a seperate header

I was trying to add documentation for an enum class which resides in its own header file. Below is what I have done so far
/**
#file
*/
namespace foo {
/**
#brief blablabla
*/
enum class MyEnum{
/**
This is ENUM_A
*/
ENUM_A,
/**
This is ENUM_B
*/
ENUM_B,
/**
This is ENUM_C
*/
ENUM_C
};
}
For some reason, the generated doc shows these 3 enum members in the list, but when I click them, it doesn't generate the page that has their own description. However this worked when I put this enum class in another class.
Could any one help me to spot what I have been missing? Thanks.
From the Doxygen documentation:
To document a member of a C++ class, you must also document the class
itself. The same holds for namespaces. To document a global C
function, typedef, enum or preprocessor definition you must first
document the file that contains it (usually this will be a header
file, because that file contains the information that is exported to
other source files).
So if you document your foo namespace, everything works fine:
/**
#brief Namespace foo
*/
namespace foo {
/**
#brief My enum
*/
enum class MyEnum{
/**
This is ENUM_A
*/
ENUM_A,
/**
This is ENUM_B
*/
ENUM_B,
/**
This is ENUM_C
*/
ENUM_C
};
}
First click on Namespace, then foo and then your enum documentation is available.
UPDATE
As #albert pointed out, there is an alternative way. According to the Doxygen documentation,
If the EXTRACT_ALL tag is set to YES doxygen will assume all
entities in documentation are documented, even if no documentation was
available. Private class members and static file members will be
hidden unless the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set
to YES
This is a nice option if you have many such scenarios in your codebase.

jsdoc : reference typedef-ed type from other module

Assuming I have a typedef type in a js module
// somewhere/foo.js
/**
* #module
*/
/**
* #typedef Foo
* #type {object}
* property {string} bar - some property
*/
Is it possible to reference this type in another module, so that in the HTML page generated by jsdoc, the type is displayed as a link to the typedef-ed module ?
I tried variations of this, but nothing seems to work...
// somewhere_else/bar.js
/**
* #module
*/
/**
* #param {somewhere/foo/Foo} foo - some param
*/
export default function doStuff(foo) {
...
}
This works for me ...
// somewhere/foo.js
/**
* #module foo
*/
/**
* #typedef module:foo.Foo
* #type {object}
* #property {string} bar - some property
*/
and ...
// somewhere_else/bar.js
/// <reference path="foo.js" />
/**
* #module bar
*/
/**
* #param {module:foo.Foo} foo - some param
*/
function doStuff(foo) {
//...
};
The above answer shows up high in search results so I'm documenting what worked for me in case it helps someone in a similar situation.
I'm using Visual Studio code for a node project with // #ts-check on all my modules. Using the above syntax hiccups on the module: syntax. Also, the code assistance doesn't work properly. It took me a while but the answer ended up being quite simple
If I have the typedef myTypedef in a module myModule then in the second module where I require myModule
mm = require(myModule)
I can use something like
/** #param {mm.myTypedef} myParamName */
The module syntax is not supported by TypeScript so if you're getting here assuming it to work, I haven't been able to get the solutions above to work.
To get it working with TypeScript use Import Types
For the OP the way I would do it is
// foo.d.ts
export type Foo = {
/**
* some property
*/
bar: string,
};
Then refer to it in the JS module as
/**
* #typedef { import("./foo").Foo } Foo
*/
/**
* #param {Foo} foo - some param
*/
export default function doStuff(foo) {
...
}
You can verify things are working on an individual file more strictly by adding the following to the beginning of the file. This will enable typescript checking in Visual Studio code for the specific file to help prepare your move to Typescript in the future.
// #ts-check
Many libraries export types from their root file, to access those in typedefs, change your import to use the import * as format.
For example:
import * as testingLibrary from '#testing-library/react';
/**
* #returns {testingLibrary.RenderResult}
*/
export function myCustomRender() { }
I've tried both of the above approaches.
Firstly, in the case of #typedef module:foo.Foo, VSCode treated the usage of Foo within the same file as any. Which I didn't find acceptable.
Secondly, when using ES6 imports the following issue emerges:
import foo from 'foo'
/** #param {foo.Foo} a - Error Foo does not exist on foo */
On the other hand VSCode recognizes import { Foo } from 'foo' without even using the JSDoc module syntax:
/**
* #module bar
*/
What's more I was also able to reference a property on the imported type, namely:
import { Foo } from 'foo'
/** #param {Foo['bar']} bar */
Note
This project uses Babel and assume compiling code which uses type imports in not feasible without a transpiler.
I'm working with vscode-powertools script which provides access to vscode module at runtime (as opposed to it being available to VSCode at edit time via the local node_modules).
If I would try to import the types with the usual jsdoc import
//#ts-check
/** #typedef {import('c:/Users/USERNAME/.vscode/extensions/ego-digital.vscode-powertools-0.64.0/node_modules/vscode').TextEditor} TextEditor */
I would be getting the File is not a module error:
File 'C:/Users/USERNAME/.vscode/extensions/ego-digital.vscode-powertools-0.64.0/node_modules/vscode/vscode.d.ts' is not a module. ts(2306)
So here's the trick I'm using to typecheck that kind of script:
//#ts-check
/// <reference types="c:/Users/USERNAME/.vscode/extensions/ego-digital.vscode-powertools-0.64.0/node_modules/vscode" />
// Allows us to reference the `vscode` module with jsdoc `#type`
async function vscodeⁱ() {if (1 == 1) return null; return import ('vscode')}
exports.execute = async (args) => {
// Allows us to reference the `vscode` module with jsdoc `#type`
const vscode = await vscodeⁱ()
/** #type {vscode} */
const vs = args.require ('vscode')
// NB: The following code is fully typed in VSCode
const windowᵛ = vs.window
const editorᵛ = windowᵛ.activeTextEditor
const start = editorᵛ.selection.start
}

How to document require-js AMD modules with jsdoc?

After many days of frustrating experimenting with jsDoc, it seems that documenting of require-js modules (AMD) has its problems. To start with:
you can't tag your module as class:
define([
"dcl/dcl",
], function (dcl) {
/**
* #class BaseClass
* See {#tutorial getting-started}
*/
var BaseClass = dcl(null,{
foo:function(a){}
});
return BaseClass;
});
jsDoc will not output foo at all! Only by changing it to
/** #module BaseClass */
define([
"dcl/dcl",
], function (dcl) {
/**
* #class module:BaseClass
*/
var BaseClass = dcl(null,{
foo:function(a){}
});
return BaseClass;
});
will enumerate foo as function in the docs. At least something but the trouble doesn't seem to end when it comes to modules. When looking at the jsdoc documentation (pretty poor), it treats Modules different; especially when it comes to constants and enums(link-able):
/** #module BaseClass */
define([
"dcl/dcl",
], function (dcl) {
/**
* #class module:BaseClass
*/
var BaseClass = dcl(null,{
/**
*
* #constant {String} module:BaseClass.COLLAPSED
* #static
* #member
* #name module:BaseClass.COLLAPSED
* */
COLLAPSED : '__wcDockerCollapsedPanel',
/**
* Add a new docked panel to the docker instance.<br>
* <b>Note:</b> It is best to use {#link wcDocker.COLLAPSED} after you have added your other docked panels, as it may ensure proper placement.
* #param {module:BaseClass.COLLAPSED} [targetPanel] - A target panel to dock relative to, or use {#link wcDocker.BaseClass} to collapse it to the side or bottom.
* #returns {wcPanel|Boolean} - The newly created panel object, or false if no panel was created.
*/
addPanel: function (targetPaneloptions) {}
});
return BaseClass;
});
Only by adding EVERYWHERE the module: prefix, your constants and enums become link-able. This looks pretty bad in the documentation. Also, I can't seem to define constants and enums in another module and link to them, memberOf doesn't help either.
So the question is: how to use jsDoc with AMD/Require-JS Modules, or how can I can make jsDoc treating AMD modules(created by var module =...) as classes?
ps: is it possible that its just buggy or not really working? Because I really tried all sorts of tags and combinations but no....Nothing really works as described in the docs.
Anyhow, any thought or links to examples are welcome.
g
I struggled with this same issue and finally came upon #lends
For you example I think all you have to change is
var BaseClass = dcl(null,{
to
var BaseClass = dcl(null, /** #lends BaseClass.prototype */{
Failure to include .prototype will result in jsdoc that defines the object literal members as static. I see you've explicitly defined COLLAPSED as static but not your method, so I'm unclear which you need or if dcl auto-detects constants and functions.

How do document a class that is returned from a function call with jsDoc

I have a large existing Javascript codebase, most of which is organized in classes created by a custom library. Most of it is similar to this:
/**
* #memberOf nameSpace.subNameSpace1
* #class
*/
nameSpace.subNameSpace1.ClassName1 = nameSpace.subNameSpace2.ClassName2.subClass({
ctor: function () {
},
/**
* method1 is a special method that does special things.
* #param config {Object}
* #returns {Boolean}
*/
method1: function (config) {
},
method2: function () {
}
})
The subClass method is defined on the Object prototype and creates a class that inherits from the object it's called on. I want to document the methods of classes that are created in this way, but unfortunately documentation like above documentation for method1 is not picked up by jsDoc (the documentation for the class itself works fine). How can I document these methods in a way that jsDoc will understand?
It turns out that using the latest version of jsdoc from npm solved the problem, and it recognizes that these methods are part of the given class if properly annotated with #function