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

@types/eslint-plugin-jsdoc or bundle .d.ts #1130

Closed
snebjorn opened this issue Jul 7, 2023 · 27 comments · Fixed by #1180
Closed

@types/eslint-plugin-jsdoc or bundle .d.ts #1130

snebjorn opened this issue Jul 7, 2023 · 27 comments · Fixed by #1180

Comments

@snebjorn
Copy link

snebjorn commented Jul 7, 2023

Motivation

With the new ESLint flat config we import plugins

import jsdoc from "eslint-plugin-jsdoc";

However that causes typescript in the VSCode to report an error due to missing type definitions.

Could not find a declaration file for module 'eslint-plugin-jsdoc'. 'myrepo/node_modules/eslint-plugin-jsdoc/dist/index.js' implicitly has an 'any' type.
Try npm i --save-dev @types/eslint-plugin-jsdoc if it exists or add a new declaration (.d.ts) file containing declare module 'eslint-plugin-jsdoc';

Current behavior

There are no types for eslint-plugin-jsdoc

Desired behavior

eslint-plugin-jsdoc should bundle the typescript types.

I'm not sure this is correct, but here's an example of the d.ts

import type { ESLint } from "eslint";

interface JSDoc extends ESLint.Plugin {
  configs: ESLint.Plugin["configs"] & {
    recommended: ESLint.ConfigData;
    ["recommended-error"]: ESLint.ConfigData;
    ["recommended-typescript"]: ESLint.ConfigData;
    ["recommended-typescript-error"]: ESLint.ConfigData;
    ["recommended-typescript-flavor"]: ESLint.ConfigData;
    ["recommended-typescript-flavor-error"]: ESLint.ConfigData;
  };
}

export default JSDoc;

Alternatives considered

A DefinitelyTyped package @types/eslint-plugin-jsdoc

@snebjorn
Copy link
Author

snebjorn commented Sep 15, 2023

#1139 added

"types": "./dist/index.d.ts",

but index.d.ts is missing from the distributed package

image

@paulshryock
Copy link

but index.d.ts is missing from the distributed package

That's because *.d.ts is explicitly ignored in .npmignore.

Looks like .npmignore should be updated to to not ignore index.d.ts.

@brettz9
Copy link
Collaborator

brettz9 commented Sep 17, 2023

Yes, sorry, I inadvertently actually added that when merely considering adding it.

I'm afraid that with some projects rather conscious about package size, that the multiple generated files may become cumbersome for some.

We could submit this to DefinitelyTyped, as you say, using what we're already able to generate.

@snebjorn
Copy link
Author

I don't understand why package size matters for a dev dependency - unless it's ridiculously large 😃

How big are the types? For comparison @typescript-eslint's types are 7 KB including .d.ts.map and 3.66 KB without. I'm not counting the AST types, as it doesn't seem relevant to using the package for linting.

Anyway, types bundled in the package is optimal but publishing a separate types package or via DefinitelyTyped also works 📦

@brettz9
Copy link
Collaborator

brettz9 commented Sep 18, 2023

For our project, it's 76 KB / 49 KB (with and without map files).

I am also unclear on why it should matter (IDEs which rely on linting tools perhaps?), but it really apparently does given how much attention projects have given us to package size (#1141 being only the most recent). I'm not keen to garner complaints on this (especially when typing is not really so critical for ESLint config files, beyond suppressing complaints in IDEs) and then having to yank the new typing feature from those who do want it.

While there are some who consider it an anti-pattern to publish within the package due to semver noise, I personally prefer it myself (projects ideally shouldn't need to track transitive dependencies themselves), but feel it is unfortunately necessary at this point.

@what1s1ove
Copy link

Hey guys!

Since Eslint 9 is on the horizon, I think it's essential to pay more attention to this issue and start preparing for the changes 🙏

image

brettz9 added a commit to brettz9/eslint-plugin-jsdoc that referenced this issue Dec 31, 2023
@brettz9
Copy link
Collaborator

brettz9 commented Dec 31, 2023

I've submitted #1180 which should do the trick. It appears that it will be sufficient and feasible to only publish the index file types.

brettz9 added a commit that referenced this issue Dec 31, 2023
@what1s1ove
Copy link

I've submitted #1180 which should do the trick. It appears that it will be sufficient and feasible to only publish the index file types.

Thank you so much!

Copy link

🎉 This issue has been resolved in version 47.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@brettz9
Copy link
Collaborator

brettz9 commented Dec 31, 2023

If someone wouldn't mind letting us how it goes...

@what1s1ove
Copy link

what1s1ove commented Dec 31, 2023

If someone wouldn't mind letting us how it goes...

This is definitely better, but still requires type casting, as index signature is used.

image

Here is the final result:

image

Perhaps you would like to make the keys (configs' names) explicit, as is done in the native recommended ESLint plugin:

image

In your case

declare const index: import('eslint').ESLint.Plugin & {
    configs: Record<'flat/recommended', 'recommended-typescript-flavor' /* and all other configs */, import('eslint').ESLint.ConfigData | {}>;
};

@brettz9
Copy link
Collaborator

brettz9 commented Dec 31, 2023

Should be fixed now in #1181 (and released in v47.0.1).

@what1s1ove
Copy link

what1s1ove commented Dec 31, 2023

Should be fixed now in #1181 (and released in v47.0.1).

image

Another error 🥲 Why is an empty object needed here?

image

@brettz9
Copy link
Collaborator

brettz9 commented Dec 31, 2023

Will users really need to get at rules like that? That {} is, IIRC, fudging things to avoid complaints about plugins: ["old-style-strings"].

@what1s1ove
Copy link

Will users really need to get at rules like that? That {} is, IIRC, fudging things to avoid complaints about plugins: ["old-style-strings"].

I modified it to the version recommended in the README (https://www.npmjs.com/package/eslint-plugin-jsdoc), and now it works 🎉 But honestly, I'm not very fond of how it looks now 😁

image

My other plugins look like this... but so far, ESLint itself doesn't know how to better incorporate them 😅

image

@brettz9
Copy link
Collaborator

brettz9 commented Dec 31, 2023

The problem with the latter is that the plugins themselves need to be reworked for flat config. A bit of a mess...

@what1s1ove
Copy link

The problem with the latter is that the plugins themselves need to be reworked for flat config. A bit of a mess...

As of now, I think everything is great, thank you for all you do!

@Logicer16
Copy link

Just tried to use it but it seems we've incorrectly used ConfigData instead of FlatConfig for the flat configs.

error TS2322: Type '{} | ConfigData<RulesRecord>' is not assignable to type 'FlatConfig'.
  Type 'ConfigData<RulesRecord>' is not assignable to type 'FlatConfig'.
    Types of property 'plugins' are incompatible.
      Type 'string[] | undefined' is not assignable to type 'Record<string, Plugin> | undefined'.
        Type 'string[]' is not assignable to type 'Record<string, Plugin>'.
          Index signature for type 'string' is missing in type 'string[]'.

@Logicer16
Copy link

I'm also experiencing a "double-default" issue when I have "moduleResolution": "NodeNext" in my tsconfig.json. This is just an issue with the types; runtime continues to work as expected. I am currently working around the issue with "moduleResolution": "Bundler".

brettz9 added a commit to brettz9/eslint-plugin-jsdoc that referenced this issue Jan 1, 2024
brettz9 added a commit that referenced this issue Jan 1, 2024
@brettz9
Copy link
Collaborator

brettz9 commented Jan 1, 2024

Just tried to use it but it seems we've incorrectly used ConfigData instead of FlatConfig for the flat configs.

Ah yes, you're right. Fix should be applied shortly.

I'm also experiencing a "double-default" issue when I have "moduleResolution": "NodeNext" in my tsconfig.json. This is just an issue with the types; runtime continues to work as expected. I am currently working around the issue with "moduleResolution": "Bundler".

Can you indicate where you're seeing the error when you don't change the moduleResolution?

Copy link

github-actions bot commented Jan 1, 2024

🎉 This issue has been resolved in version 47.0.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

@Logicer16
Copy link

Can you indicate where you're seeing the error when you don't change the moduleResolution?

src/index.ts:4:46 - error TS2339: Property 'configs' does not exist on type 'typeof import("~/Developer/a/node_modules/eslint-plugin-jsdoc/dist/index")'.

4 const jsdocConfig: Linter.FlatConfig = jsdoc.configs[
                                               ~~~~~~~

This builds without issue:

const jsdocConfig: Linter.FlatConfig = jsdoc.default.configs[
  "flat/recommended-typescript-flavor-error"
];

But fails at runtime:

const jsdocConfig = jsdoc.default.configs["flat/recommended-typescript-flavor-error"];
                                  ^

TypeError: Cannot read properties of undefined (reading 'configs')
    at file:///Users/jamesross/Developer/a/dist/index.js:2:35
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
    at async loadESM (node:internal/process/esm_loader:34:7)
    at async handleMainPromise (node:internal/modules/run_main:113:12)

Node.js v20.10.0

If you need help reproducing, the following files are all it seems to need for the error to occur.

src/index.ts
import jsdoc from "eslint-plugin-jsdoc";
import {Linter} from "eslint";

const jsdocConfig: Linter.FlatConfig = jsdoc.configs[
  "flat/recommended-typescript-flavor-error"
];
package.json
{
  "name": "a",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "devDependencies": {
    "eslint": "^8.56.0",
    "eslint-plugin-jsdoc": "^47.0.2",
    "typescript": "^5.3.3"
  }
}
tsconfig.json
{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "dist"
  }
}

@brettz9
Copy link
Collaborator

brettz9 commented Jan 1, 2024

Hmmm... I've confirmed the issue with your sample, but for some reason, we don't see the problem in regular "JavaScript-with-JSDoc-as-TypeScript" mode.

Adding the following to a JavaScript file:

import jsdoc from "eslint-plugin-jsdoc";

jsdoc.configs[
  "flat/recommended-typescript-flavor-error"
];

shows up with tooltip info properly:

image

@brettz9
Copy link
Collaborator

brettz9 commented Jan 1, 2024

It appears it can be fixed by our switching to native ESM (with fallback to CJS) (or by using babel's plugin for add-module-exports, but I think we'll go with the former).

@what1s1ove
Copy link

what1s1ove commented Jan 2, 2024

Hey @brettz9, all

Now it looks perfect! Thank you for all you do! Here is my migration PR - what1s1ove/whatislove.dev#298

and here is my eslint.config.js - https://github.com/what1s1ove/whatislove.dev/blob/main/eslint.config.js

@brettz9
Copy link
Collaborator

brettz9 commented Jan 2, 2024

Can you indicate where you're seeing the error when you don't change the moduleResolution?

src/index.ts:4:46 - error TS2339: Property 'configs' does not exist on type 'typeof import("~/Developer/a/node_modules/eslint-plugin-jsdoc/dist/index")'.

4 const jsdocConfig: Linter.FlatConfig = jsdoc.configs[
                                               ~~~~~~~

Try release v48.0.1

@Logicer16
Copy link

Try release v48.0.1

Sorry for the silence, just got around to checking and everything now seems to be working as expected. Thank you so much for all your work.

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

Successfully merging a pull request may close this issue.

5 participants