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

Fix: clone config before validating (fixes #12592) #13034

Merged
merged 16 commits into from Jun 16, 2020

Conversation

anikethsaha
Copy link
Member

@anikethsaha anikethsaha commented Mar 12, 2020

Prerequisites checklist

  • I have read the contributing guidelines.
  • The team has reached consensus on the changes proposed in this pull request. If not, I understand that the evaluation process will begin with this pull request and won't be merged until the team has reached consensus.

What is the purpose of this pull request? (put an "X" next to an item)

[ ] Documentation update
[X] Bug fix (template)
[ ] New rule (template)
[ ] Changes an existing rule (template)
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[ ] Other, please explain:

What changes did you make? (Give an overview)

Cloning the rule config and other configs before validating them as they get mutated with default values when used useDefault : true in agv.
I couldn't find any other entry point for this issue other than this, do let me know if any!

Is there anything you'd like reviewers to focus on?

fixes #12592

@eslint-deprecated eslint-deprecated bot added the triage An ESLint team member will look at this issue soon label Mar 12, 2020
@anikethsaha anikethsaha changed the title Fix: clone config/rules before validating [WIP] Fix: clone config/rules before validating Mar 12, 2020
@anikethsaha anikethsaha changed the title [WIP] Fix: clone config/rules before validating Fix: clone config/rules before validating Mar 12, 2020
@anikethsaha anikethsaha changed the title Fix: clone config/rules before validating Fix: clone config before validating (fixes #12592) Mar 17, 2020
Copy link
Member

@kaicataldo kaicataldo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not actually finding where the validate function is used, and I'm wondering if this is dead code. Please let me know if I'm missing something.

Additionally, we're using ajv's useDefaults option (see here), and I think cloning it in the validation function means that these default values won't be used by the rules. Can we clone the config at a higher level and then pass that to the validator function?

We'll also want to include some tests for this, though I don't think this PR should require any rule test changes. I think we'll want to test that a config object doesn't get mutated after a run of the linter.

@kaicataldo kaicataldo added accepted There is consensus among the team that this change meets the criteria for inclusion bug ESLint is working incorrectly core Relates to ESLint's core APIs and features and removed triage An ESLint team member will look at this issue soon labels Mar 17, 2020
@kaicataldo
Copy link
Member

Thanks for working on this!

@anikethsaha
Copy link
Member Author

Can we clone the config at a higher level and then pass that to the validator function?

By higher level, you meant where we are reading/getting the config? then I think it needs to pass two configs to the validator one cloned and one original. cause only the cloned one will be validated. the original one will be passed to the rules

@kaicataldo
Copy link
Member

Is there a reason we can't clone the config as soon as we have the full resolved config and use that for validation and then pass that to the rules?

@anikethsaha
Copy link
Member Author

i will try that 👍

@anikethsaha anikethsaha force-pushed the fixes-12592 branch 3 times, most recently from b35883f to aad0f64 Compare March 25, 2020 12:34
@anikethsaha
Copy link
Member Author

@kaicataldo I updated the cloning to a higher level.
I think I might have missed some other entry points for configs.

Also, do you think it would be helpful to add a clone here instead

if (configData) {
return this._normalizeConfigData(configData, {
...ctx,
filePath: plugin.filePath,
name: `${ctx.name} » plugin:${plugin.id}/${configName}`
});
}

Like this

if (configData) {
  const clonedConfigData = lodash.cloneDeep(configData);
  return this._normalizeConfigData(
    clonedConfigData,
    plugin.filePath,
    `${importerName} » plugin:${plugin.id}/${configName}`
  );
}

Copy link
Member

@aladdin-add aladdin-add left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It had been cloned when ajv's useDefaults was introduced( see here
), but was removed somehow.

  • I agreed it better to be in a higher level: reading config -> cloning config -> validating config.
  • a test case is required!

thanks for working on this!

@anikethsaha
Copy link
Member Author

@aladdin-add can you check if the current one is fine ?

let me know if this has to be changed. after that, I will add some tests

@aladdin-add
Copy link
Member

I'd suggest it in something like linter.js, than in getRuleOptions -- it could be cloned multi-times.

@anikethsaha
Copy link
Member Author

I'd suggest it in something like linter.js, than in getRuleOptions

I think the current one in this PR is something like this.

earlier I planned to have it clone and validate in config-validator.js alone. In this way, it will clone every config irrespective of where they are coming from.

But I think the current one is the entry point for the config (not for the directives,)

@anikethsaha
Copy link
Member Author

@kaicataldo can you please take a look if this is the fine place to clone?

@nzakas
Copy link
Member

nzakas commented Apr 23, 2020

@kaicataldo can you take a look at this again?

@kaicataldo
Copy link
Member

Apologies for the delay! I've been sick the last few weeks and am just getting caught up.

lib/linter/linter.js Outdated Show resolved Hide resolved
lib/linter/linter.js Outdated Show resolved Hide resolved
@anikethsaha
Copy link
Member Author

anikethsaha commented Jun 11, 2020

@nzakas feel free to finish this or I can try to finish this as well if the final direction has been set whether to use JSON.parse(JSON.stringify(rules)) or not.

Either way works for me.

👍

@nzakas
Copy link
Member

nzakas commented Jun 11, 2020

The direction has been set. If you're able to update this, that would be great as I don't have a lot of time. But if you can't finish it, then I can take it over. It just might take some time for me to finish.

@anikethsaha
Copy link
Member Author

anikethsaha commented Jun 11, 2020

The direction has been set.

@nzakas So are we moving forward with JSON.parse(JSON.stringify(rules)) instead of the current clone logic ?

If you're able to update this, that would be great as I don't have a lot of time. But if you can't finish it, then I can take it over. It just might take some time for me to finish.

ok cool, I will try to finish this weekend then.

@nzakas
Copy link
Member

nzakas commented Jun 12, 2020

Correct, and thanks 👍

@anikethsaha
Copy link
Member Author

Done 👍

Copy link
Member

@mysticatea mysticatea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The direction LGTM, thank you!
I have some small suggestions.

lib/cli-engine/config-array-factory.js Show resolved Hide resolved
lib/cli-engine/config-array-factory.js Outdated Show resolved Hide resolved
Copy link
Member

@mysticatea mysticatea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thank you for your contribution!

Copy link
Member

@nzakas nzakas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for sticking with this! We really appreciate it.

@anikethsaha
Copy link
Member Author

@nzakas @mysticatea I think we need to revert this ? 7fb45cf#r40036492

Cause I guess users are using non serialized data for the config

*
* Refer https://github.com/eslint/eslint/issues/12592
*/
const clonedRulesConfig = rules && JSON.parse(JSON.stringify((rules)));
Copy link
Sponsor Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unfortunately i never saw this PR; JSON cloning should never be used, especially since eslint config values can be regexes, Infinity, NaN, and other things that don't survive JSON serialization.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ljharb We did try to avoid json cloning using this. But we tried using lodash cloneDeepWith with customizer but that had different issues like circular ref issue,

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a BREAKING CHANGE for a lot of plugins which support options via

regexes, Infinity, NaN, and other things that don't survive JSON serialization

For example: https://github.com/sindresorhus/eslint-plugin-unicorn/blob/master/docs/rules/filename-case.md#ignore

anikethsaha added a commit to anikethsaha/eslint that referenced this pull request Jun 19, 2020
aladdin-add added a commit that referenced this pull request Jun 30, 2020
kaicataldo pushed a commit that referenced this pull request Jul 3, 2020
* Revert "Fix: Replace Infinity with Number.MAX_SAFE_INTEGER (fixes #13427) (#13435)"

This reverts commit de77c11.

* Revert "Fix: clone config before validating (fixes #12592) (#13034)"

This reverts commit 7fb45cf.
@eslint-deprecated eslint-deprecated bot locked and limited conversation to collaborators Dec 14, 2020
@eslint-deprecated eslint-deprecated bot added the archived due to age This issue has been archived; please open a new issue for any further discussion label Dec 14, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion archived due to age This issue has been archived; please open a new issue for any further discussion bug ESLint is working incorrectly core Relates to ESLint's core APIs and features
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Schema validation modifies exported config object in .eslintrc.js
8 participants