Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@typedef scopes #31

Open
pentacular opened this issue Jun 20, 2020 · 6 comments
Open

@typedef scopes #31

pentacular opened this issue Jun 20, 2020 · 6 comments

Comments

@pentacular
Copy link
Contributor

what would you like to see added?

I've been reading about scopes, and I'm not entirely sure that I understand fully how it's supposed to work.

This looks to me as though it ought to create a global typedef, which can be referred to as Foo in any location.

/**
 * @global
 * @typedef {string} Foo
 */

In which case, a simple import './foo'; should be enough to link it in.

There is also /** @module */ which will derive a module name from the current file, unless specified.

It kind of looks like we are effectively inserting an implicit /** @module */ at the top of each file.

I'm not sure if this is correct -- without it, should @typedefs belong in the global scope?

@orzechowskid
Copy link
Owner

This looks to me as though it ought to create a global typedef, which can be referred to as Foo in any location.

I can't seem to find conclusive evidence for or against that. the documentation for @global says that the tag applies to the symbol being described, ignoring its actual scope in the source file. I interpreted "symbol being described" as "the next line of code", not "the current JSDoc block", though I could be convinced otherwise.

I suspect the scope-related tags are really meant for code documentation generation tools like swagger, but that suspicion is also something for which I can't find any evidence.

In which case, a simple import './foo'; should be enough to link it in.

given the following two files:

// foo.js
/**
 * @typedef {string} Foo
 */

// index.js
import './foo';

/** @type {Foo} */
const x = 'foo type';

I don't see how we can discover the Foo type in foo.js from inside index.js without analyzing every module imported by index.js (and by extension every other file in the module dependency graph rooted at that source file). that seems non-performant.

It kind of looks like we are effectively inserting an implicit /** @module */ at the top of each file.

yep, exactly. behind the scenes, typedefs are tied to their containing file; it's to distinguish between @typedef {boolean} Foo defined locally and @typedef {number} Foo defined externally but imported into the file being linted.

the following example is not something supported by this plugin today, I don't think, but is supported in my IDE and is how I document things in other projects:

/**
 * @return {import('../types').Foo}
 */
function myFunc() {
  return { name: 'Alice', age: 25 };
}

if I use an external type many times in one file, I'll re-typedef it:

/** @typedef {import('../types').Foo} Foo */

/**
 * @return {Foo}
 */
function myFunc() {
  return { name: 'Alice', age: 25 };
}

it's not ideal, but neither is scanning your entire source tree to discover @typedefs every time you lint-on-idle in your IDE.

@pentacular
Copy link
Contributor Author

I think you're already rescanning it when you hit an import.

You could change it to only rescan the magic import(foo).bar type syntax, which would reduce it to the tree of type related modules, but you can't avoid that since you need properties of the imported type beyond the name.

Given that, I suggest you might as well keep it simple and follow imports as is.

I'll take a futher look at @global, but jsdoc is a mess. :)

@pentacular
Copy link
Contributor Author

l found the test cases in jsdoc, and I think I see how it must work now.

https://github.com/jsdoc/jsdoc/blob/master/packages/jsdoc/test/fixtures/typedeftag.js
In this case the symbol is in the typedef
/** @typedef {Object} CalculatorBattery */

In this case it follows.
/** @typedef {string} */
calc.Operator;

I'll put in a PR for jsdoc to add an @global @typedef test case to nail down the semantics.

@pentacular
Copy link
Contributor Author

pentacular commented Jun 21, 2020

I also found this existing test case.

https://github.com/jsdoc/jsdoc/blob/9142fe8858a919332fbc8eb7c08c376ff70d35a5/packages/jsdoc/test/specs/tags/typedeftag.js#L52

When a symbol has a @typedef tag with a name and no scope, the scope defaults to `global`.

as in the test file for CalculatorBattery

/** @typedef {(string|number)} calc.NumberLike */
    
/** @typedef {string} */
calc.Operator;

/** @typedef {calc.NumberLike} calc.Result */
calc.Outcome;

/** @param {calc.NumberLike} x A number or a string. */
calc.readNumber = function(x) {
};

/** @typedef {Object} CalculatorBattery */

So I think the current behavior on eslint-plugin-typelint is non-conformant with jsdoc.

Supporting and adding /** @module */ at the start of the file should produce similar behavior to what we have at the moment, although I think the prefix needs changing for that case.

@pentacular
Copy link
Contributor Author

I've added test cases to jsdoc in jsdoc/jsdoc#1801

At least for jsdoc the following are true

a.js

/** @typedef {number} x */

x has global scope, and has qualified name "x".

b.js

/** @module b */
/** @typedef {number} b */

b has inner scope, and a qualified name of "module:b~b".

c.js

/** @module c */
/**
 * @global
 * @typedef {number} c
 */

c has global scope and has qualified name "c".

d.js

/** @module */
/** @typedef {number} d */

Has inner scope and the qualified name "module:[[string0]]~d".
(Although I think the string0 comes from the test harness).

Which at least makes it clear what the semantics for jsdoc are. :)
They weren't exactly what I expected, either.

@pentacular
Copy link
Contributor Author

Ah, now I see where this is coming from -- it looks like it's a typedoc thing rather than a jsdoc thing.

By default, Typedoc creates a Module for each ES6 Module (each file).

https://github.com/christopherthielen/typedoc-plugin-external-module-name

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants