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

Change Request: Standardized export of flat configs to enable programmatic detection #18095

Open
1 task done
bmish opened this issue Feb 8, 2024 · 11 comments
Open
1 task done
Labels
core Relates to ESLint's core APIs and features enhancement This change enhances an existing feature of ESLint

Comments

@bmish
Copy link
Sponsor Member

bmish commented Feb 8, 2024

ESLint version

8.56.0

What problem do you want to solve?

ESLint configs have traditionally been exported by ESLint plugins under a standard configs object (alongside the rules object). This has allowed tooling like eslint-doc-generator and lintbase.com to automatically detect/analyze configs and generate documentation regarding them including the list of configs, which rules belong to which configs, etc.

New flat configs can be exported in a variety of ways, including as an arbitrary file export from the plugin, such as require('eslint-plugin-ember/configs/recommended') in this example I worked on, and not necessarily in the configs object exported by the plugin.

For existing plugins that want to support both legacy and flat versions of their configs while maintaining backwards-compatability, I've typically seen them leave the configs object for legacy configs, and add file exports for the new flat configs.

To my knowledge, since there aren't strict requirements around how or where flat configs are exported from, the user has to manually look up in the plugin's README to find out what the configs are and how exactly to import and use them (including whether they are arrays or objects). As you can imagine, depending on the README to discover configs is not conducive to automated tooling.

What do you think is the correct solution?

Note: See updated proposal in: #18095 (comment)

Could there be a convention or requirement for how plugins should export flat configs? Presumably, this would keep legacy config exporting the same through the configs object for backwards-compatability so plugins can support both config types, at least for some time.

One idea is to require or suggest plugins to export a new configurations object containing a mapping of config name to each loaded flat config.

And what about recommendations around the direct file path entrypoint for exporting flat configs? I've seen plugins using eslint-plugin-example/configs/config-name or variations of this. Perhaps we could at least recommend a path format.

Ideally, any convention or requirement would enable programmatic discoverability of flat configs, with the added benefit of simply making it easier to use flat configs.

Participation

  • I am willing to submit a pull request for this change.

Additional comments

Related:

@bmish bmish added enhancement This change enhances an existing feature of ESLint core Relates to ESLint's core APIs and features labels Feb 8, 2024
@mdjermanovic
Copy link
Member

We could recommend a certain way of exporting configurations from plugins, but I don't think we could enforce it because ESLint doesn't load configurations from plugins.

@nzakas
Copy link
Member

nzakas commented Feb 14, 2024

As a reminder: when you move an issue to "Feedback Needed" please mention @eslint/eslint-team to ensure people get notifications.

@nzakas
Copy link
Member

nzakas commented Feb 14, 2024

I don't have any strong feelings around this. To me, the flexibility to be able to create your package in whatever structure you want is part of the selling point of flat config (and something people asked for in eslintrc frequently).

If we're going to recommend exporting an object, then I think it needs to be configs to go along with the existing plugin structure.

If we're going to recommend string imports then package-name/configs/config-name makes sense to me.

@JoshuaKGoldberg
Copy link
Contributor

I'm in favor of establishing a recommendation. I think there's value both in allowing people to be flexible and establishing alignment guidelines for programmatic usage. 👍

@bmish
Copy link
Sponsor Member Author

bmish commented Feb 18, 2024

Thinking about this some more, I agree with @nzakas that utilizing the existing configs exported object makes sense.

Ideally, all configs would be represented in this configs object, as they always have been, and we wouldn't need individual string exports like package-name/configs/config-name.

The reason some plugins have resorted to string exports is because they want to maintain the same name for their configs, e.g. the recommended config is available in legacy format at configs.recommended through the original configs object or in flat format at package-name/configs/recommended (qunit example, ember example).

Other plugins (like eslint-plugin-unicorn) have named their flat configs with flat/ so they can be used like configs['flat/recommended'] from the standard configs object.

Both of these approaches work, yet I'd consider them temporary solutions. String exports are not ideal because they aren't discoverable in the standard configs object. flat/ prefixed config naming will be redundant once flat is the only config system.

Out of both of these approaches, I would recommend the flat/ prefixing approach as it has better discoverability for tooling and reuses the existing configs object instead of introducing additional exports.

But regardless of which approach is chosen, I would recommend plugins to eventually remove the string exports or flat/ prefixing as a breaking change in a subsequent major version. If the major version comes during ESLint v9, then the legacy configs can just be suffixed with -legacy like recommended-legacy (or prefixed with legacy/) to continue supporting them. If the major version comes after ESLint v10, then the legacy configs can be removed entirely. So the end state should be that configs are all back in the exported configs object with the original naming like recommended.

Recommending standard config prefixes and suffixes would also enable us to detect which config is legacy vs. flat and thus whether a plugin supports flat config, as in these easily-distinguishable examples:

  • recommended (legacy) and flat/recommended
  • legacy-recommended and recommended (flat)

Perhaps we can include these recommendations in the Configuration Files (New) or Configuration Migration Guide docs in a section on backwards compatibility / how to support both flat and legacy config / plugins exports.

@nzakas
Copy link
Member

nzakas commented Feb 19, 2024

Out of both of these approaches, I would recommend the flat/ prefixing approach as it has better discoverability for tooling and reuses the existing configs object instead of introducing additional exports.

I'd prefer not to use the name "flat" at all. The only reason we talk about flat config now is to disambiguate it from eslintrc, but in the future, there will be no reason to say anything other than "config". This is why we recommend the "-legacy" suffix for eslintrc configs.

Regarding discoverability: it's trivial to determine if something is a flat config vs. an eslintrc config, so I'm not sure if it's important to encode that information into the name for tooling purposes. There are certain keys that exist at the top level in eslintrc that aren't there in flat config. Could we not just use that to determine what kind of config it is?

@bmish
Copy link
Sponsor Member Author

bmish commented Feb 20, 2024

The -legacy suffix makes sense. But renaming a config to use that suffix is a breaking change. So plugins have needed an intermediary solution for adding flat support--thus some of them are (temporarily) using the flat/ prefix.

I do think our migration story/recommendation should cover this intermediary support period (temporarily supporting both legacy and flat without breaking changes), because that's where a lot of the inconsistency is coming into play.

Basically, my recommendation would be to use flat/ naming while adding flat support, and then eliminating flat/ naming in favor of -legacy naming during a subsequent major version. Let me know if you prefer another way of doing it.

In terms of discoverability, as long as configs are all in the configs object, tooling should be able to detect them. And then yes I imagine we could detect if a config is flat vs. legacy by the properties present.

However, having a consistent naming pattern like flat/foo or foo-legacy or foo encodes additional information in that these are really just the same config but for different config systems. That way, tooling could say stuff like "This plugin offers a foo config, here's a link to the legacy version of it, and here's a link to the flat version of it."

@nzakas
Copy link
Member

nzakas commented Feb 27, 2024

I understand why some plugins have adopted flat/ -- it's just not something I want to encourage, as I think the term "flat" only has meaning during this transition period. Ideally, the word "flat" never appears in our docs when we hit v10, and leaving that term lying around will only cause confusion. I'd like to prepare the ecosystem for the post-transition world.

Copy link

Oops! It looks like we lost track of this issue. What do we want to do here? This issue will auto-close in 7 days without an update.

@nzakas
Copy link
Member

nzakas commented Apr 2, 2024

@bmish thoughts on my last comment?

@github-actions github-actions bot removed the Stale label Apr 2, 2024
@bmish
Copy link
Sponsor Member Author

bmish commented Apr 24, 2024

If we don't want to encourage flat in any naming, that's OK. The most important point of this ticket is just that all configs are included in the configs object. Providing suggested naming for plugins to use during the migration period would be a nice to have on top of that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Relates to ESLint's core APIs and features enhancement This change enhances an existing feature of ESLint
Projects
Status: Feedback Needed
Development

No branches or pull requests

4 participants