exercism / typescript

Exercism exercises in TypeScript.
https://exercism.org/tracks/typescript
MIT License
153 stars 160 forks source link

ESLint cannot find already installed plugins when linting exercises in local environment #1386

Closed konradkozubek closed 4 months ago

konradkozubek commented 1 year ago

Issue

Hello, I hope that it is the right place to mention this issue.

I recently started TypeScript track and found out that there seems to be a problem with linting configuration when working locally, both in Two Fer and Resistor Color Duo exercises (so probably in all exercises in the track).

ESLint cannot find two plugins, which are installed as dependencies of @exercism/eslint-config-typescript package, which is present in package.json file.

TL;DR

It seems to be a long known issue in ESLint, that seems to be resolved with introduction of the new config system (see the last comment in mentioned issue). The new config system will be used by default in v9, but it also can be used now in v8 after some configuration (I haven't tried that).

However, there is a simple workaround to fix this issue. ESLint can find those plugins, if they are explicitly present in the package.json file. @exercism/eslint-config-typescript package declares eslint-plugin-import@npm:^2.27.5 and @typescript-eslint/eslint-plugin@npm:^5.59.9 as dependencies, so adding "eslint-plugin-import": "npm:^2.27.5", and "@typescript-eslint/eslint-plugin": "npm:^5.59.9", to the object in "devDependencies" in package.json solves the issue.

Following sections explain the details.

Steps to reproduce error

I am working on macOS Monterey, using Node v18.17.0 installed by nvm.

After running exercism download --exercise=two-fer --track=typescript, entering exercise directory and installing dependencies with yarn install, run yarn lint:ci.

Expected behavior

ESLint working normally.

Encountered behavior

ESLint cannot find two plugins, even though they are installed as dependencies of @exercism/eslint-config-typescript. Running

yarn lint:ci

gives following error:

Oops! Something went wrong! :(

ESLint: 8.47.0

ESLint couldn't find the plugin "eslint-plugin-import".

(The package "eslint-plugin-import" was not found when loaded as a Node module from the directory "/Users/konrad/Git_repositories/exercism-typescript-two-fer-eslint-test/two-fer".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

    npm install eslint-plugin-import@latest --save-dev

The plugin "eslint-plugin-import" was referenced from the config file in ".eslintrc.cjs#overrides[0] » @exercism/eslint-config-typescript".

Running:

yarn info -R eslint-plugin-import

confirms, that the package is installed, because it is a dependency of @exercism/eslint-config-typescript. However, running

yarn add -D eslint-plugin-import@npm:^2.27.5

fixes this problem - ESLint is now able to find eslint-plugin-import package, but cannot find another one. (Version range is the same as specified by @exercism/eslint-config-typescript package.) Running

yarn lint:ci

now gives another error:

Oops! Something went wrong! :(

ESLint: 8.47.0

ESLint couldn't find the plugin "@typescript-eslint/eslint-plugin".

(The package "@typescript-eslint/eslint-plugin" was not found when loaded as a Node module from the directory "/Users/konrad/Git_repositories/exercism-typescript-two-fer-eslint-test/two-fer".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

    npm install @typescript-eslint/eslint-plugin@latest --save-dev

The plugin "@typescript-eslint/eslint-plugin" was referenced from the config file in ".eslintrc.cjs#overrides[1] » @exercism/eslint-config-typescript/maintainers".

Again, running

yarn info -R @typescript-eslint/eslint-plugin

confirms, that the package is installed, because it is a dependency of @exercism/eslint-config-typescript. Similarly, running

yarn add -D @typescript-eslint/eslint-plugin@npm:^5.59.9

fixes this problem - ESLint is now able to find @typescript-eslint/eslint-plugin package, too. (Version range is the same as specified by @exercism/eslint-config-typescript package.) Running

yarn lint:ci

now shows, that ESLint is working correctly.

Solution

As I said in TL;DR section, the issue can be quickly fixed by adding eslint-plugin-import@npm:^2.27.5 and @typescript-eslint/eslint-plugin@npm:^5.59.9 as development dependencies to package.json of the exercise project. It is important to use the version ranges specified by @exercism/eslint-config-typescript package, because running yarn add -D @typescript-eslint/eslint-plugin and installing the latest version of this package leads to another ESLint error: Definition for rule '@typescript-eslint/no-parameter-properties' was not found, as this rule was deleted meanwhile (typescript-eslint.io blog post announcing typescript-eslint v6 informs about removal of this deprecated rule).

It seems that with currently used ESLint configuration that is the way to go by quickly solving the issue, however maybe using the new config system of ESLint is worth trying - maybe then plugins provided as @exercism/eslint-config-typescript package dependencies would be visible to ESLint.

github-actions[bot] commented 1 year ago

Hello. Thanks for opening an issue on Exercism. We are currently in a phase of our journey where we have paused community contributions to allow us to take a breather and redesign our community model. You can learn more in this blog post. As such, all issues and PRs in this repository are being automatically closed.

That doesn't mean we're not interested in your ideas, or that if you're stuck on something we don't want to help. The best place to discuss things is with our community on the Exercism Community Forum. You can use this link.%20The%20new%20config%20system%20will%20be%20used%20by%20default%20in%20v9,%20but%20it%20also%20can%20be%20used%20now%20in%20v8%20after%20%5Bsome%20configuration%5D(https://eslint.org/docs/latest/use/configure/migration-guide#start-using-flat-config-files)%20(I%20haven't%20tried%20that).%0D%0A%0D%0AHowever,%20there%20is%20a%20simple%20workaround%20to%20fix%20this%20issue.%20ESLint%20can%20find%20those%20plugins,%20if%20they%20are%20explicitly%20present%20in%20the%20%60package.json%60%20file.%20%60@exercism/eslint-config-typescript%60%20package%20declares%20%60eslint-plugin-import@npm:%5E2.27.5%60%20and%20%60@typescript-eslint/eslint-plugin@npm:%5E5.59.9%60%20as%20dependencies,%20so%20adding%20%60%22eslint-plugin-import%22:%20%22npm:%5E2.27.5%22,%60%20and%20%60%22@typescript-eslint/eslint-plugin%22:%20%22npm:%5E5.59.9%22,%60%20to%20the%20object%20in%20%60%22devDependencies%22%60%20in%20%60package.json%60%20solves%20the%20issue.%0D%0A%0D%0AFollowing%20sections%20explain%20the%20details.%0D%0A%0D%0A##%20Steps%20to%20reproduce%20error%0D%0A%0D%0AI%20am%20working%20on%20macOS%20Monterey,%20using%20Node%20v18.17.0%20installed%20by%20%60nvm%60.%0D%0A%0D%0AAfter%20running%20%60exercism%20download%20--exercise=two-fer%20--track=typescript%60,%20entering%20exercise%20directory%20and%20installing%20dependencies%20with%20%60yarn%20install%60,%20run%20%60yarn%20lint:ci%60.%0D%0A%0D%0A##%20Expected%20behavior%0D%0A%0D%0AESLint%20working%20normally.%0D%0A%0D%0A##%20Encountered%20behavior%0D%0A%0D%0AESLint%20cannot%20find%20two%20plugins,%20even%20though%20they%20are%20installed%20as%20dependencies%20of%20%60@exercism/eslint-config-typescript%60.%20Running%0D%0A%0D%0A%60%60%60bash%0D%0Ayarn%20lint:ci%0D%0A%60%60%60%0D%0A%0D%0Agives%20following%20error:%0D%0A%0D%0A%60%60%60%0D%0AOops!%20Something%20went%20wrong!%20:(%0D%0A%0D%0AESLint:%208.47.0%0D%0A%0D%0AESLint%20couldn't%20find%20the%20plugin%20%22eslint-plugin-import%22.%0D%0A%0D%0A(The%20package%20%22eslint-plugin-import%22%20was%20not%20found%20when%20loaded%20as%20a%20Node%20module%20from%20the%20directory%20%22/Users/konrad/Git_repositories/exercism-typescript-two-fer-eslint-test/two-fer%22.)%0D%0A%0D%0AIt's%20likely%20that%20the%20plugin%20isn't%20installed%20correctly.%20Try%20reinstalling%20by%20running%20the%20following:%0D%0A%0D%0A%20%20%20%20npm%20install%20eslint-plugin-import@latest%20--save-dev%0D%0A%0D%0AThe%20plugin%20%22eslint-plugin-import%22%20was%20referenced%20from%20the%20config%20file%20in%20%22.eslintrc.cjs#overrides%5B0%5D%20%C2%BB%20@exercism/eslint-config-typescript%22.%0D%0A%60%60%60%0D%0A%0D%0ARunning:%0D%0A%0D%0A%60%60%60bash%0D%0Ayarn%20info%20-R%20eslint-plugin-import%0D%0A%60%60%60%0D%0A%0D%0Aconfirms,%20that%20the%20package%20is%20installed,%20because%20it%20is%20a%20dependency%20of%20%60@exercism/eslint-config-typescript%60.%20However,%20running%0D%0A%0D%0A%60%60%60bash%0D%0Ayarn%20add%20-D%20eslint-plugin-import@npm:%5E2.27.5%0D%0A%60%60%60%0D%0A%0D%0Afixes%20this%20problem%20-%20ESLint%20is%20now%20able%20to%20find%20%60eslint-plugin-import%60%20package,%20but%20cannot%20find%20another%20one.%20(Version%20range%20is%20the%20same%20as%20specified%20by%20%60@exercism/eslint-config-typescript%60%20package.)%20Running%0D%0A%0D%0A%60%60%60bash%0D%0Ayarn%20lint:ci%0D%0A%60%60%60%0D%0A%0D%0Anow%20gives%20another%20error:%0D%0A%0D%0A%60%60%60%0D%0AOops!%20Something%20went%20wrong!%20:(%0D%0A%0D%0AESLint:%208.47.0%0D%0A%0D%0AESLint%20couldn't%20find%20the%20plugin%20%22@typescript-eslint/eslint-plugin%22.%0D%0A%0D%0A(The%20package%20%22@typescript-eslint/eslint-plugin%22%20was%20not%20found%20when%20loaded%20as%20a%20Node%20module%20from%20the%20directory%20%22/Users/konrad/Git_repositories/exercism-typescript-two-fer-eslint-test/two-fer%22.)%0D%0A%0D%0AIt's%20likely%20that%20the%20plugin%20isn't%20installed%20correctly.%20Try%20reinstalling%20by%20running%20the%20following:%0D%0A%0D%0A%20%20%20%20npm%20install%20@typescript-eslint/eslint-plugin@latest%20--save-dev%0D%0A%0D%0AThe%20plugin%20%22@typescript-eslint/eslint-plugin%22%20was%20referenced%20from%20the%20config%20file%20in%20%22.eslintrc.cjs#overrides%5B1%5D%20%C2%BB%20@exercism/eslint-config-typescript/maintainers%22.%0D%0A%60%60%60%0D%0A%0D%0AAgain,%20running%0D%0A%0D%0A%60%60%60bash%0D%0Ayarn%20info%20-R%20@typescript-eslint/eslint-plugin%0D%0A%60%60%60%0D%0A%0D%0Aconfirms,%20that%20the%20package%20is%20installed,%20because%20it%20is%20a%20dependency%20of%20%60@exercism/eslint-config-typescript%60.%20Similarly,%20running%0D%0A%0D%0A%60%60%60bash%0D%0Ayarn%20add%20-D%20@typescript-eslint/eslint-plugin@npm:%5E5.59.9%0D%0A%60%60%60%0D%0A%0D%0Afixes%20this%20problem%20-%20ESLint%20is%20now%20able%20to%20find%20%60@typescript-eslint/eslint-plugin%60%20package,%20too.%20(Version%20range%20is%20the%20same%20as%20specified%20by%20%60@exercism/eslint-config-typescript%60%20package.)%20Running%0D%0A%0D%0A%60%60%60bash%0D%0Ayarn%20lint:ci%0D%0A%60%60%60%0D%0A%0D%0Anow%20shows,%20that%20ESLint%20is%20working%20correctly.%0D%0A%0D%0A##%20Solution%0D%0A%0D%0AAs%20I%20said%20in%20TL;DR%20section,%20the%20issue%20can%20be%20quickly%20fixed%20by%20adding%20%60eslint-plugin-import@npm:%5E2.27.5%60%20and%20%60@typescript-eslint/eslint-plugin@npm:%5E5.59.9%60%20as%20development%20dependencies%20to%20%60package.json%60%20of%20the%20exercise%20project.%20It%20is%20important%20to%20use%20the%20version%20ranges%20specified%20by%20%60@exercism/eslint-config-typescript%60%20package,%20because%20running%20%60yarn%20add%20-D%20@typescript-eslint/eslint-plugin%60%20and%20installing%20the%20latest%20version%20of%20this%20package%20leads%20to%20another%20ESLint%20error:%20%60Definition%20for%20rule%20'@typescript-eslint/no-parameter-properties'%20was%20not%20found%60,%20as%20this%20rule%20was%20deleted%20meanwhile%20(%5Btypescript-eslint.io%20blog%20post%5D(https://typescript-eslint.io/blog/announcing-typescript-eslint-v6/#rule-breaking-changes)%20announcing%20typescript-eslint%20v6%20informs%20about%20removal%20of%20this%20deprecated%20rule).%0D%0A%0D%0AIt%20seems%20that%20with%20currently%20used%20ESLint%20configuration%20that%20is%20the%20way%20to%20go%20by%20quickly%20solving%20the%20issue,%20however%20maybe%20using%20the%20new%20config%20system%20of%20ESLint%20is%20worth%20trying%20-%20maybe%20then%20plugins%20provided%20as%20%60@exercism/eslint-config-typescript%60%20package%20dependencies%20would%20be%20visible%20to%20ESLint.%0D%0A&category=typescript) to copy this into a new topic there.


Note: If this issue has been pre-approved, please link back to this issue on the forum thread and a maintainer or staff member will reopen it.

angelikatyborska commented 1 year ago

@SleeplessByte Can you reopen? I can confirm that this problem happens. But I had to start a fresh exercise to be able to reproduce, I'm not sure yet why it didn't happen on an exercise I already started before, which has an identical package.json.

SleeplessByte commented 1 year ago

image

I just downloaded resistor-color-trio. It worked out of the box.

You can see in https://github.com/exercism/typescript/blob/main/exercises/practice/resistor-color-trio/package.json#L19-L25 that eslint is declared to resolve the issue as mentioned. I did not experience that I needed to declare "the sub plugins". This setup we've been using to maintain both TS and JS for over a year now.

Could it be that you @angelikatyborska or you @konradkozubek have not yet updated your exercise? If yes, can you tell me where it's happening? Additionally, after running yarn to install, can you please use the Command Pallete in VSCode to forcefully restart ESLint. Can you also see if there are errors in the Output tab like in my screenshot? Finally, can you tell me which version of Yarn you are using and can you confirm that you are using the following extension:

Name: ESLint
Id: dbaeumer.vscode-eslint
Description: Integrates ESLint JavaScript into VS Code.
Version: 2.4.2
Publisher: Microsoft
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint
angelikatyborska commented 1 year ago

@SleeplessByte It happens to me on completely fresh exercises. Earlier today I tried on matrix, right now I tried on darts, both of which I never attempted to solve before.

Normally I use yarn 1.22.19 installed globally via asdf, but for some reason the Exercism TS exercise forces my yarn to be version 3.6.0.

I tested this with my IDE closed so that any IDE Eslint plugins do not interfere. Normally I use Webstorm. I never rely on Eslint run via the IDE, I always run it myself in the terminal.

angelika in ~/Exercism/typescript
$ node -v
v18.17.0
angelika in ~/Exercism/typescript
$ yarn -v
1.22.19
angelika in ~/Exercism/typescript
$ exercism download --exercise=darts --track=typescript

Downloaded to
/Users/angelika/Exercism/typescript/darts
angelika in ~/Exercism/typescript
$ cd darts
angelika in ~/Exercism/typescript/darts
$ node -v
v18.17.0
angelika in ~/Exercism/typescript/darts
$ yarn -v
3.6.0
angelika in ~/Exercism/typescript/darts
$ yarn install
➤ YN0000: ┌ Resolution step
➤ YN0032: │ fsevents@npm:2.3.2: Implicit dependencies on node-gyp are discouraged
➤ YN0002: │ @exercism/typescript-darts@workspace:. doesn't provide @babel/core (p4e0b8), requested by babel-jest
➤ YN0000: │ Some peer dependencies are incorrectly met; run yarn explain peer-requirements <hash> for details, where <hash> is the six-letter p-prefixed code
➤ YN0000: └ Completed in 6s 794ms
➤ YN0000: ┌ Fetch step
➤ YN0013: │ yallist@npm:3.1.1 can't be found in the cache and will be fetched from the remote registry
➤ YN0013: │ yallist@npm:4.0.0 can't be found in the cache and will be fetched from the remote registry
➤ YN0013: │ yargs-parser@npm:21.1.1 can't be found in the cache and will be fetched from the remote registry
➤ YN0013: │ yargs@npm:17.7.2 can't be found in the cache and will be fetched from the remote registry
➤ YN0013: │ yocto-queue@npm:0.1.0 can't be found in the cache and will be fetched from the remote registry
➤ YN0000: └ Completed in 2s 293ms
➤ YN0000: ┌ Link step
➤ YN0000: │ ESM support for PnP uses the experimental loader API and is therefore experimental
➤ YN0007: │ core-js@npm:3.30.2 must be built because it never has been before or the last one failed
➤ YN0007: │ core-js@npm:3.32.0 must be built because it never has been before or the last one failed
➤ YN0000: └ Completed in 1s 435ms
➤ YN0000: Done with warnings in 10s 595ms
angelika in ~/Exercism/typescript/darts
$ yarn lint:ci

Oops! Something went wrong! :(

ESLint: 8.47.0

ESLint couldn't find the plugin "eslint-plugin-import".

(The package "eslint-plugin-import" was not found when loaded as a Node module from the directory "/Users/angelika/Exercism/typescript/darts".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

    npm install eslint-plugin-import@latest --save-dev

The plugin "eslint-plugin-import" was referenced from the config file in ".eslintrc.cjs#overrides[0] » @exercism/eslint-config-typescript".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.
SleeplessByte commented 1 year ago

Thank you. This helps. I'll try to make it work for your use case.

SleeplessByte commented 1 year ago

@angelikatyborska can you try adding the following line to the exercise .yarnrc.yml:

nodeLinker: node-modules

It doesn't matter if it's above or below the yarnPath line. Afterwards run yarn install again. It should create a folder node_modules in the exercise folder and inside you should find eslint-plugin-import (not nested, directly as subfolder).

If this works, we unfortunately will have to revert PnP because of some shitty decisions eslint have taken in the past.


I have read all the threads. I neither agree with the original resolution (and completely agree with Sindre's assesment and commentary) and I don't think the "flat structure" will work as well as we want it to. It also has been experimental for over a year so I am not keen to introduce that here. Futhermore, adding the dependencies directly to the exercise is exactly what we do not want, nor do we want peerDepedencies. The students should be able to just install the exercise and not worry about these things at all, nor should the exercise be invalidated when a plugin updates.

A decent workaround may be https://www.npmjs.com/package/@rushstack/eslint-patch, but I need to explore that. It is also listed as workaround for the Plug'n'Play issue you both are experiencing as listed here: https://yarnpkg.com/features/pnp#native-support

angelikatyborska commented 1 year ago

@SleeplessByte

It should create a folder node_modules in the exercise folder and inside you should find eslint-plugin-import (not nested, directly as subfolder).

It did, and now yarn lint:ci works.

SleeplessByte commented 1 year ago

@konradkozubek you can use the method above to make it work in the meantime. I will work on implementing eslint-patch.

konradkozubek commented 1 year ago

Sorry, I've been quite busy these last few days, so I'm responding now.

Yes, adding nodeLinker: node-modules to .yarnrc.yml does temporarily solve the problem - ESLint can find both packages and works correctly. It would be great if it worked with PnP, though. I didn't know about www.npmjs.com/package/@rushstack/eslint-patch, I hope it will solve the problem the right way.


@SleeplessByte

I neither agree with the original resolution (and completely agree with Sindre's assesment and commentary) and I don't think the "flat structure" will work as well as we want it to.

As I mentioned in the initial comment, I considered adding plugin packages to exercise projects as only a quick workaround not requiring changing of ESLint configuration, and I thought that using the new config system would solve the problem the right way - but I understand, that you don't want to use it in favor of @rushstack/eslint-patch. I also completely agreed with Sindre's assesment.

Futhermore, adding the dependencies directly to the exercise is exactly what we do not want, nor do we want peerDepedencies. The students should be able to just install the exercise and not worry about these things at all, nor should the exercise be invalidated when a plugin updates.

Of course I meant that in this quick workaround - making plugin packages peer dependencies of @exercism/eslint-config-typescript - not the students would have to install them, but they would already be present in downloaded package.json. I agree that peer dependencies are not the way to go, as Sindre assessed.

SleeplessByte commented 1 year ago

I'll let both of you know when you can upgrade to test out the new way of doing it!

WigglyDon commented 1 year ago

Hi there. This issue was linked in a thread for a separate issue related to Yarn 3 and Jest testing locally on the typescript track.

https://forum.exercism.org/t/issue-with-local-jest-type-definitions-yarn-3-and-jest/6867/7

I'm just posting to raise the possibility that Yarn PnP related issues may be more widespread than this in the track, and possibly there are more things out there going wrong that haven't been reported yet due to people not having had the opportunity to thoroughly test the track.

I have been unable to solve a missing type dependency for jest without somehow involving node_modules which from what I understand completely defeats the purpose of using Yarn PnP.

I don't really know if these are for sure related, but since this issue was linked on the provided post, I thought I'd poke my nose in and say hey :)

konradkozubek commented 1 year ago

@WigglyDon I replied in your thread https://forum.exercism.org/t/issue-with-local-jest-type-definitions-yarn-3-and-jest/6867/7. When using Yarn PnP, I fixed problems with VS Code not recognizing the type definitions for Jest by following the official Yarn guide on how to integrate VS Code with Yarn PnP: Editor SDKs | Yarn. However, if you follow @SleeplessByte's advice of adding nodeLinker: node-modules line to .yarnrc.yml before running yarn install, which temporarily fixes issue with ESLint, then Yarn PnP is not used and you don't have to install Yarn's SDK and only need to select installed TypeScript version in VS Code's settings.

SleeplessByte commented 4 months ago

Solved by #1504.

SleeplessByte commented 4 months ago

Fixed by https://github.com/exercism/typescript/commit/4da603e8ebafc4cbfbde56190a5f572e61c598f0