-
Notifications
You must be signed in to change notification settings - Fork 335
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
Add Experimental support of Flat Config #1522
Conversation
@dbaeumer Hi, could you take a look when you have time? Support by VSCode's ESLint extension is a a huge step towards the spread of ESLint's new config system. (I'm not an ESLint member though 😅 ) |
@uhyo unfortunately this has to wait a little until next month. I am very busy with task I have to complete in other areas. |
@dbaeumer may be someone else can review this PR and take care about release (as alpha/beta, doesn't matter)? It doesn't look so complicated, but really blocks adoption of trash-less ESLint config. |
@@ -394,6 +394,7 @@ export namespace ESLintClient { | |||
synchronize: { | |||
fileEvents: [ | |||
Workspace.createFileSystemWatcher('**/.eslintr{c.js,c.cjs,c.yaml,c.yml,c,c.json}'), | |||
Workspace.createFileSystemWatcher('**/eslint.config.js'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You will also need to add this file to this filter:
vscode-eslint/client/src/client.ts
Line 114 in e345da0
const configFileFilter: DocumentFilter = { scheme: 'file', pattern: '**/.eslintr{c.js,c.yaml,c.yml,c,c.json}' }; |
server/src/eslint.ts
Outdated
// 8.21.0 <= version, experimental endpoint that supports Flat Config | ||
ESLint: undefined; | ||
CLIEngine: undefined; | ||
FlatESLint: ESLintClassConstructor; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the use of this type this seems to refer the exports of ESLint main's entry point. If @dbaeumer can confirm that this was the original intention, then this last object is wrong, since the FlatESLint
export is still not part of the public API. Moreover, I don't see why we would need to make ESLint
undefined here? As of today ESLint is still exposing that class.
server/src/eslint.ts
Outdated
@@ -947,13 +970,51 @@ export namespace ESLint { | |||
return resultPromise; | |||
} | |||
|
|||
function getESLintManifest(workingDirectory: DirectoryItem | undefined, configType: ConfigType | undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I truly dislike having these heuristics for figuring out the configuration type to use, since they might not match how ESLint discovers the configuration file to use and then we might end up with inconsistent linting experiences when using the CLI command versus using this extension.
I'm just giving my 2¢ here, but for preserving backwards compatibility and easing the maintenance of this extension while ESLint upgrades its API, I think we should follow a similar approach as the one used with the withESLintClass
setting when moving from CLIEngine
to ESLint
. We could have an opt-in withFlatConfig
setting that when set to true (and using the right ESLint version) will import the corresponding FlatConfig
and use that API, else it will default to the current behavior until ESLint replaces the ESLint
class with the flat one and then that becomes the new default. I'm aware that this would mean that if someone has an eslint.config.js
file then they need an extra step of toggling the withFlatConfig
setting to make this extension work but with an experimental API that's still changing, I think this is a reasonable sacrifice.
server/src/eslint.ts
Outdated
[ '.eslintrc.yaml', false ], | ||
[ '.eslintrc.yml', false ] | ||
const projectFolderIndicators: [string, boolean, ConfigType | undefined][] = [ | ||
[ 'eslint.config.js', true, 'flat-config' ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would find an array of typed objects easier to understand here.
server/src/eslint.ts
Outdated
if (ESLintModule.hasFlatESLintClass(library) && useESLintClass) { | ||
return new library.FlatESLint(newOptions); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why have this if the if-block in line 1015 would already handle it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also it seems like you're using the withESLintClass
setting in a way that doesn't align with the documented description of the setting.
@MariaSolOs Thank you for review! I recreated this PR with the config approach. This is indeed more reasonable; the clutter in the I named the new config Hope you can recheck this. |
The code changes actually look good to me. However, I would like to ask to clean up the playground you added and have one small example that uses a flat config. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clean up playground as pointed out in general comment.
@dbaeumer Thanks! I cleaned up the playground. |
@@ -155,6 +155,7 @@ export type ConfigurationSettings = { | |||
validate: Validate; | |||
packageManager: PackageManagers; | |||
useESLintClass: boolean; | |||
experimentalUseFlatConfig: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To remain consistent with the useESLintClass
setting, I would remove the experimental
suffix here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for confusing you, but I'd like to keep the name experimental
because, unlike useESLintClass
, this config will be unnecessary in the future when Flat Config is considered stable. At that time the regular ESLint
class will have the Flat Config support as described here. Then this config can be removed and users can use Flat Config without additional configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand now. Thanks for explaining!
"scope": "resource", | ||
"type": "boolean", | ||
"default": false, | ||
"description": "Enable support of experimental Flat Config (aka eslint.config.js, supported by ESLint version 8.21 or later)." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned previously, I would remove the experimental
here, since flat config will eventually become stable and we don't want to have separate settings for the experimental
and stable
APIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can dismiss this comment now that you've explained why we're using the experimental
name :)
package.json
Outdated
}, | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not too important, but unless you did this on purpose, you might have a formatter making changes here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I reverted the formatting changes.
package.json
Outdated
} | ||
"items": { | ||
"properties": { | ||
"severity": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the change here? Did you replace tabs with spaces?
const projectFolderIndicators: { | ||
fileName: string; | ||
isRoot: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for following my suggestion! This looks much cleaner 💄
// During Flat Config is considered experimental, | ||
// we need to import FlatESLint from 'eslint/use-at-your-own-risk'. | ||
// See: https://eslint.org/blog/2022/08/new-config-system-part-3/ | ||
const eslintPath = settings.experimentalUseFlatConfig ? 'eslint/use-at-your-own-risk' : 'eslint'; | ||
if (nodePath !== undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest first trying to check if the 'eslint'
entry point exports a FlatESLint
object. If it doesn't and the setting is enabled, try the experimental path. That way we won't need to update this code when flat config becomes stable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As described in this comment the 'eslint'
entry point will never export a FlatESLint
object, but the name ESLint
is kept when Flat Config is stablized.
When Flat Config becomes stable, what user needs to do is to disable the experimentalUseFlatConfig
config.
server/src/eslint.ts
Outdated
} | ||
} else if (lib.FlatESLint === undefined) { | ||
settings.validate = Validate.off; | ||
connection.console.error(`The eslint library loaded from ${libraryPath} doesn\'t neither exports a FlatESLint class.`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's a typo in this error message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, fixed 🙂
I also updated error messages so it helps users after Flat Config is stabilized.
server/src/eslint.ts
Outdated
} | ||
} else if (library.CLIEngine === undefined && library.ESLint === undefined) { | ||
settings.validate = Validate.off; | ||
connection.console.error(`The eslint library loaded from ${libraryPath} doesn\'t neither exports a CLIEngine nor an ESLint class. You need at least eslint@1.0.0`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
neither exports
?
server/src/eslint.ts
Outdated
@@ -851,11 +851,11 @@ export namespace ESLint { | |||
if (lib === undefined) { | |||
settings.validate = Validate.off; | |||
if (!settings.silent) { | |||
connection.console.error(`Failed to load eslint library from ${libraryPath}. See output panel for more information.`); | |||
connection.console.error(`Failed to load eslint library from ${libraryPath}. If you are using ESLint lower than v8.21, try upgrading ESLint. If you are using a fairly new ESLint version, try disabling 'experimentalUseFlatConfig' config. See output panel for more information.`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the nit, but I think a clearer message would be "If you are using ESLint v8.21 or earlier, try upgrading it. For newer versions, try disabling the 'experimentalUseFlatConfig' setting. See the output panel for more information."
.
Error messages should be as clear as possible to help users encountering them :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than that, everything else LGTM! Thanks a lot @uhyo for your patience and effort, I'm sure a lot of people will very much appreciate your contribution ❤️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed the error message! Thank you for patiently working with me.
@MariaSolOs since you guided most of that coding can you please approve the changes as well. Then I will merge it into the main branch. |
@dbaeumer @uhyo I tested the changes locally and everything LGTM. Let's ship this! 🚀 |
Amazing, thanks for the work from everyone here! 🙌 I take it from the milestone this will be available in the From semver I would have imagined that this would actually go into the |
@dbaeumer is probably going to be the one handling the release, and although I do agree with @karlhorky that |
|
Ok thanks, I'm not sure I understand this explanation in this Release Notes docs section, so I did a PR to try to challenge my assumptions about it: |
Fixes #1518
This PR adds a support of ESLint's new configuration format.
This feature is enabled by setting
eslint.experimentalUseFlatConfig
to true.Note that currently
FlatESLint
needs to be imported from a special endpointeslint/use-at-your-own-risk
. Therefore we should treat this feature as experimental.