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
feat: Flat config support in Linter (refs #13481) #15185
Conversation
Since feedback is a bit slow these days, I'm going to convert to a draft and keep adding changes to this PR. |
With At this point, I think the best path forward is to encourage people to switch to using This situation will only arise when someone is using flat config, which case Thoughts? |
I don't think there's any way to reliably find the path, because the config gets just the loaded parser object.
Agree, this was already predicted in the RFC:
|
@@ -0,0 +1,138 @@ | |||
/** | |||
* @fileoverview Globals for ecmaVersion/sourceType | |||
* @author Nicholas C. Zakas |
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.
Moved globals here since the list is much smaller without environments, allowing us to update more easily and also support ES3 correctly (right now we still add JSON
when ecmaVersion
is 3.
sourceType: "module", | ||
parser: "@/espree", | ||
parserOptions: {} | ||
} |
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.
Updating the defaults as briefly discussed in #14588. I think it makes sense to assume people will be using ESM and always want the latest ecmaVersion
.
{ | ||
files: ["**/*.cjs"], | ||
languageOptions: { | ||
sourceType: "commonjs" |
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.
For .cjs
files, I think it makes sense to opt them into "commonjs" sourceType.
Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
Okay, I think I've got everything |
I just upgraded Espree and eslint-scope to the versions that support |
Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
I could find only 3 differences with eslintrc configs before and after this change.
In theory, this could affect parsing, depending on how the handling of options is implemented in a custom parser, although it does not seem likely. Thoughts? I checked espree,
Similar to the previous point, this doesn't really change how |
|
|
lib/linter/linter.js
Outdated
// check for options-based processing | ||
if (options.preprocess || options.postprocess) { | ||
return this._verifyWithFlatConfigArrayAndProcessor(textOrSourceCode, config, options); | ||
} |
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.
In the if (config.processor)
path, _verifyWithFlatConfigArray
calls _verifyWithFlatConfigArrayAndProcessor
with options.preprocess
, and then _verifyWithFlatConfigArrayAndProcessor
calls _verifyWithFlatConfigArray
with the same options.preprocess
, so this will run config.processor.preprocess()
again on its output:
const { Linter } = require("eslint");
const linter = new Linter({ configType: "flat" });
const config = {
files: ["*.md"],
processor: {
preprocess(text, filename) {
console.log(`Called with text = '${text}', filename = '${filename}'`);
return [{ text: "bar", filename: "0.js" }];
},
postprocess() {
return [];
}
}
};
linter.verify("foo", config, "a.md");
// logs:
// Called with text = 'foo', filename = 'a.md'
// Called with text = 'bar', filename = 'a.md/0_0.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.
Huh, nice catch. I'll look at that.
Just FYI: It was a little bit difficult to understand that you were pointing out a problem here. When you state the behavior you're seeing, it would help me out a lot if you'd say something like, "This behavior is unexpected and I don't see it when using eslintrc." This is probably just the brain fog, but little hints like saying "unexpected" make it a lot easier for me to decipher descriptions.
if ( | ||
parserOptions.sourceType === "module" && | ||
parserOptions.ecmaFeatures && | ||
parserOptions.ecmaFeatures.globalReturn | ||
) { | ||
parserOptions.ecmaFeatures.globalReturn = false; | ||
} |
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.
_verifyWithoutProcessors
(resolveParserOptions
) is overwriting globalReturn
regardless of the parser, but _verifyWithFlatConfigArrayAndWithoutProcessors
will do that only if the parser is Espree?
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.
Yes. I don’t think we should be messing around with other parsers’ options. Ideally, the parser itself will throw an error with an unexpected combination of options. I think we should do that, too, but it would be a breaking change.
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.
LGTM, thanks!
@btmills can you give this a once-over before I merge? |
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 only found one potential functional change where this branch is currently passing void 0
as parserName
. I left a couple inline suggestions, but if the void 0
question is answered, this can be merged as-is.
I'm very excited to see this go into the release, even if undocumented. Great work!
checker(context) { | ||
return { | ||
Program() { | ||
assert.strictEqual(context.languageOptions.ecmaVersion, 2015); |
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.
It would be possible for this test and the next few, which also use this pattern, to pass if Program()
were never called. Elsewhere you declare let ecmaVersion;
above, assign it here, and move the assertion to the line after the verify()
call so that the assertion is guaranteed to be called. Not a required change, but I wanted to point it out in case you prefer that pattern.
Co-authored-by: Brandon Mills <btmills@users.noreply.github.com>
Co-authored-by: Brandon Mills <btmills@users.noreply.github.com>
Co-authored-by: Brandon Mills <btmills@users.noreply.github.com>
Co-authored-by: Brandon Mills <btmills@users.noreply.github.com>
Prerequisites checklist
What is the purpose of this pull request? (put an "X" next to an item)
[ ] Documentation update
[ ] Bug fix (template)
[ ] New rule (template)
[ ] Changes an existing rule (template)
[ ] Add autofixing to a rule
[ ] Add a CLI option
[x] Add something to the core
[ ] Other, please explain:
What changes did you make? (Give an overview)
Updated
Linter
to acceptFlatConfigArray
as an argument. To do so, I added a newconfigType
option that must be set to"flat"
. When set to"flat"
, thedefineRule
,defineRules
, anddefineParser
methods all throw an error because there is no good way to mimic this functionality with flat config. (People can instead define a plugin directly in the config.) Ultimately, we'll end up removing these methods.I've only added enough tests to verify each of the initial paths for flat config. In a future pull request I'll work on converting the existing tests to work with flat config. I just don't want to wait too long before merging these changes in order to avoid conflicts.
Note: These changes are a prerequisite for the
ESLint
class changes.Task list:
configType
is"flat"
context.parserPath
compatibilitycontext.languageOptions
doesn't existlanguageOptions.ecmaVersion
is year-based (2015 instead of 6)languageOptions.ecmaVersion
translates toparserOptions.ecmaVersion
languageOptions.ecmaVersion
adds globals for the appropriate versionlanguageOptions.ecmaVersion: 3
only has ES3 globalslanguageOptions.sourceType: "commonjs"
adds Node.js globalslanguageOptions.sourceType: "commonjs"
switches parser options to parse globalreturn
Is there anything you'd like reviewers to focus on?
Is there any danger in merging this?