Support unexported module functions
Closed this issue · 17 comments
Let's say I've got the following JSDoc to describe a callback:
/**
* Callback used to provide access to altering a remote request prior to the request being made.
*
* @callback PrepareRequestCallback
*
* @param {object} req - The Superagent request object
* @param {string} location - The location being retrieved
* @param {function} callback - First callback
*/
Right now, I have an NPM module that wants to describe a callback but it's not something exported. If I use @callback
, I get the following error when generating the TSD:
Can't add member 'module:path-loader~PrepareRequestCallback' to parent item 'undefined'. Unsupported member type: 'alias'
If I replace @callback
with @function
, no error but the function is exported and I end up with something like this:
/**
* Utility that provides a single API for loading the content of a path/URL.
*/
declare module 'path-loader' {
// ...
/**
* Callback used to provide access to altering a remote request prior to the request being made.
* @param req - The Superagent request object
* @param location - The location being retrieved
* @param callback - First callback
*/
export function PrepareRequestCallback(req: object, location: string, callback: Function): void;
// ...
}
I need a way within a @module
to describe a callback so that it gets generated as declare function {MY_CALLBACK}
so that it's documented but not exported. (I'm new to TypeScript and TSD so bear with me please.)
And I could be doing all of this wrong. I just want someone to know what the expectation is when writing a callback is. But it's not an exported function.
The issue about alias
being an unsupported kind
seems to happen once I try to throw things into a module
. Without module
, @typedef {function} MyCallback
works just fine and is declared as declare type MyCallback
. But once I try to define MyCallback
as an internal type of a module
, that error happens.
So I can't tell if there are multiple things going on but any help would be appreciated. If you want some context, I'm trying to do this for path-loader and eventually for others once I get the simplest project done.
I changed the description of this because it seems like @callback
works fine when not using @module
as well. I've updated path-loader
to have the desired @callback
support, with generated TSD and updated the repo. What I want is to be able to use @module
so that LoadOptions
, PrepareRequestCallback
and ProcessResponseCallback
are declare type
within the module
and only load
is exported.
I just got it somewhat working by marking PrepareRequestCallback
and ProcessResponseCallback
as @global
but why I don't have to do that for LoadOptions
is beyond me. It would be slick if they all were treated as non-global but I can't seem to get @callback
to work with @module
at this time.
I've also tried @callback module:path-loader~PrepareRequestCallback
and I get a similar error:
Can't add member 'module:path-loader~PrepareRequestCallback' to parent item 'undefined'. Unsupported member type: 'alias'
I'll start debugging code.
I'm not sure, maybe there are more problems.
First about the case that you just want an unexported function inside a module, like that:
declare module myModule {
function myFunction(...): void;
}
I think the correct way would be, to use the @inner
tag for myFunction
(http://usejsdoc.org/tags-inner.html).
Unfortunately this will not work for now because there is a bug. (At the moment, you will get an unexported function, if you use @private
. But then you have to call jsdoc with the private flag...).
I think we can fix this bug next week or so.
Is that the right way to do this? I'm new to TypeScript in general. I've looked into some documentation and I can't tell if declare type
or declare function
is the right thing. All I want to do is document a callback that isn't exported (it shouldn't be) and isn't an instantiable thing. I just want to document it for tooling purposes.
Actually a callback is a typedef. So for example if you have this documentation:
/**
* @callback testCallback
* @param {string} testCBParam
*/
/**
* @function myFunction
* @param {string} myString
* @param {testCallback} myCallback
*/
you will get this output:
/**
* @param testCBParam
*/
declare type testCallback = (testCBParam: string)=>void;
/**
* @param myString
* @param myCallback
*/
declare function myFunction(myString: string, myCallback: testCallback): void;
The problem is, if you add the callback to a module. I just reproduced that. You can add the function and the callback to a namespace or you can add only the function to a module. That works fine. But if you add the callback to a module you will get the error message that you mentioned above:
Can't add member 'module:myTestModule~testCallback' to parent item 'undefined'. Unsupported member type: 'alias'
This seems to be another bug! and I think we also can fix this during next week.
That's correct. :)
I will gladly help with a PR, this is blocking me. Let me see if I can figure out where this is failing and go from there.
It looks like in the module
handling, the kind is alias
and that is just not converted to the real kind
it's an alias of. I have a little code that does this but what ends up happening is that the generated code is export function myFunction(myString: string, myCallback: testCallback): void;
instead of declare function myFunction(myString: string, myCallback: testCallback): void;
. So progress is made but I need to figure out how declare
vs. export
is handled. Once I do that, I should have a PR. I think the alias
handling is where the magic is but not sure what all values for type.kind
are when kind
is alias
, I'm not sure.
It looks like the JSDoc name and scope are not being used to identify whether or not something should be declared or exported. When I look at the JSDoc details for my file, it's clear that module.exports.load
should be exported by its name (starts with exports.
or module.exports.
) and by its scope (static
) whereas my callback/typedefs, which are defined for documentation/typing information alone, should not be exported based on their name (does not start with exports.
or module.exports.
) and their scope (inner
) .
Any reason why these details are not used when identifying if/when things should be declared vs. exported?
I stand corrected, you are using .scope
but I'm not sure how inner
ends up being exported. I'll continue looking.
The problem with aliases in modules can simply be fixed by adding case alias
to case module
in function prepareResults
.
Any reason why these details are not used when identifying if/when things should be declared vs. exported?
Well we export by default everything that is not marked private. But you are right, that is not correct! We should rather use the export and the static flag. (We just added the behaviour for the private flag like JSDoc: @private but we forgot to change this case.)
I added the fixes here:
https://github.com/tineheller/jsdoc-tsd/blob/master/src/core/jsdoc-tsd-parser.ts
Additional I added two examples that use inner
and exported
functions in modules
https://github.com/tineheller/jsdoc-tsd/blob/master/exampleProject/src/core/myModule2.js
https://github.com/tineheller/jsdoc-tsd/blob/master/exampleProject/src/core/myModule3.js
I'm really sorry but I cannot merge and publish this before next week. So if you need it now, maybe you can work with local changes.
Your repository works fine. :) I've tested it and it works. Now to figure out why @returns {Promise<*>}
becomes Promise.<*>
instead of Promise.<any>
and I'll be in business. (I already reported this in #38)
ok, these fixes seems to work. Just to clarify it:
The function handleFlags is used to identify if a member has to be exported or not (or should be static or abstract). This function gets called here for every parsed item. Maybe this helps you to understand how scopes are mapped.
To describe a callback parameter, there are several ways to do this, and as often, there is no "right way". You can declare a function
/**
* @callback
*/
function a() {
}
/**
* @param {a} callback Callback function
*/
function b(callback) { }
or you can use arrow functions, for example:
/**
* @param {() => string} callback Callback function
*/
function b(callback) { }
As @tineheller mentioned, the alias-case has to �be added to the case module
part, for workspaces it works as expected. But it's good that you tested it with modules. I don't use modules that often (in javascript) so it's harder for me to find issues :)