Import types in a parent file not working jsdoc - jsdoc

I try to import a type from a parent file that have the #typedef but it's not working when the type is in a parent file.
My code not working : /** #typedef { import('../../jsdoc/logics.jsdoc.js').ColumnItem } ColumnItem */
My code working : /** #typedef { import('./logics.jsdoc.js').ColumnItem } ColumnItem */
So as you can see, I need to move the file logics.jsdoc.js to get the import working.
Do you know how to do ?

Related

How does one make jsdoc actually output docs?

I'm trying to get jsdoc (version 3.6.7, using node 16) to turn my documented js code into actual documentation, but no matter what I do it just generates an out directory with an index.html that is primarily empty lines, rather than documentation. I've asked about this over on the issue tracker (after I searched the docs and the web for information on what one might be doing wrong to get jsdoc to generate empty files, but I can't for the life of me find anything useful that addresses that) but since it's been a few days, it feels useful to ask here as well, so that an answer in either place can be cross posted.
Running the jsdoc command does not flag any errors with the input, and completes with a normal zero exit code but generates nothing useful, so hopefully someone here's run into his before and can explain what is necessary in addition to the follow code to actually get jsdoc to generate docs.
An example of code that has no errors according to jsdoc, but also yields no docs whatsoever:
import { Errors } from "../errors.js";
import { Models } from "./models.js";
/**
* Several paragraphs of text that explain this class
*
* #class
* #namespace model
*/
export class Model {
/**
* #ignore
*/
static ALLOW_INCOMPLETE = Symbol();
/**
* Also several paragraphs explaining the use of this function.
*
* #static
* #param {*} data
* #param {*} allowIncomplete (must be Model.ALLOW_INCOMPLETE to do anything)
* #returns {*} a model instance
* #throws {*} one of several errors
*/
static create = function (data = undefined, allowIncomplete) {
return Models.create(
this,
data,
allowIncomplete === Model.ALLOW_INCOMPLETE
);
};
/**
* code comment that explains that if you're reading
* this source, you should not be using the constructor,
* but should use the .create factory function instead.
*
* #ignore
*/
constructor(caller, when) {
if (!caller || typeof when !== "number") {
const { name } = this.__proto__.constructor;
throw Errors.DO_NOT_USE_MODEL_CONSTRUCTOR(name);
}
}
}
Running this with jsdoc test.js yields an out dir with an index.html and test.js.html file, the first containing some thirty newlines of "no docs here" with boilerplate wrapper HTML code, and the second containing the original source code with nothing else useful either.
What else does one need to do to get jsdoc to actually generate documentation here?
I have fixed it by not using export infront of classes, instead exporting them at the end of the file. like this:
import { Errors } from "../errors.js";
import { Models } from "./models.js";
/**
* Several paragraphs of text that explain this class
*
* #class
* #namespace model
*/
class Model {
/**
* #ignore
*/
static ALLOW_INCOMPLETE = Symbol();
/**
* Also several paragraphs explaining the use of this function.
*
* #static
* #param {*} data
* #param {*} allowIncomplete (must be Model.ALLOW_INCOMPLETE to do anything)
* #returns {*} a model instance
* #throws {*} one of several errors
*/
static create = function (data = undefined, allowIncomplete) {
return Models.create(
this,
data,
allowIncomplete === Model.ALLOW_INCOMPLETE
);
};
/**
* code comment that explains that if you're reading
* this source, you should not be using the constructor,
* but should use the .create factory function instead.
*
* #ignore
*/
constructor(caller, when) {
if (!caller || typeof when !== "number") {
const { name } = this.__proto__.constructor;
throw Errors.DO_NOT_USE_MODEL_CONSTRUCTOR(name);
}
}
}
export {Model}
Turns out this was posted too early: taking the time to start at the official documentation for classes over on https://jsdoc.app/tags-class.html and running that example through jsdoc works perfectly fine, and subsequently building out that example to match the actual file's code yields working documentation just fine, too.
And in this specific case, there were several problems:
adding #namespace paired with #class was the main problem. Neither were necessary, but the #namespace entry changes how jsdoc parses the rest of a file's documentation, where if methods are to show up, they must use a #name property that includes that namespace. As that was not the case here, nothing ended up showing in the documentation.
having an #ignore on the constructor function, rather than using the #hideconstructor property on the class meant that even with #namespace removed, no documentation got written. JSdoc treats the class docs heading and the constructor as the same thing, so #ignoreing the constructor is treated the same as ignoring the entire class.
Fixing both mistakes, and removing the unnecessary #class at the top, gives perfectly fine documentation:
import { Errors } from "../errors.js";
import { Models } from "./models.js";
/**
* Several paragraphs of text that explain this class
*
* #hideconstructor
*/
export class Model {
/**
* #ignore
*/
static ALLOW_INCOMPLETE = Symbol();
/**
* Also several paragraphs explaining the use of this function.
*
* #static
* #param {*} data
* #param {*} allowIncomplete (must be Model.ALLOW_INCOMPLETE to do anything)
* #returns {*} a model instance
* #throws {*} one of several errors
*/
static create = function (data = undefined, allowIncomplete) {
return Models.create(
this,
data,
allowIncomplete === Model.ALLOW_INCOMPLETE
);
};
/**
* code comment that explains that if you're reading
* this source, you should not be using the constructor,
* but should use the .create factory function instead.
*/
constructor(caller, when) {
if (!caller || typeof when !== "number") {
const { name } = this.__proto__.constructor;
throw Errors.DO_NOT_USE_MODEL_CONSTRUCTOR(name);
}
}
}

How do I assign type as instance of a class using jsdoc?

I have Example class and a something function where the first argument is example, how do I document something so that the example argument is typed as an instance of Example?
class Example {}
function something (example) {
}
If the class is discoverable by the function, as in, it's in the same file.
/**
* #param {Example} example
*/
function something (example) {
}
If jsdoc can't find it, then imports work like this:
/**
* #param {import('./example')} example
*/
function something (example) {
}
Or this depending on how Example is exported.
/**
* #param {import('./example')['Example']} example
*/
function something (example) {
}

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

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.

How to use classes from other module in JSDoc annotations

Best explained with an example:
some-class.js
function SomeClass() { /* ... */ }
SomeClass.prototype.doSomething = function() { /* ... */ };
export function createSomeClass() {
return new SomeClass();
}
index.js
import { createSomeClass } from './some-class';
/**
* #param {SomeClass} someClass
*/
function foo(someClass) {
someClass.doSomething();
}
var someClass = createSomeClass();
someClass.doSomething();
This code leads to errors in VSCodes TypeScript checker and won't provide code completion for the class inside foo:
An alternative would be to export the class constructor and import it in index.js which gives me full code completion but adds a warning due to the unused import of the class:
What I also don't like about this solution is that it "leaks" the class to the outside which is not necessary otherwise due to the createSomeClass factory.
Is there some way to have full annotations & code completion without the unused import of the class?

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
}