Skip to content

Rule require-meta-default-options potentially conflicts with ESLintUtils.RuleCreator #545

@Zamiell

Description

@Zamiell

Hello and thanks for the excellent plugin! This is a quick question about the eslint-plugin/require-meta-default-options rule.

In my ESLint plugin, I copied the patterns from typescript-eslint, because I assume that they represent best-practice in the ecosystem. Here is the source code for a typical typescript-eslint rule. As you can see, they put defaultOptions at the root level, but not at the meta level.

Now, I am introducing eslint-plugin-eslint-plugin to my plugin for the first time. However, it flags that all of my rules are failing require-meta-default-options. But fixing this seems tricky.

Failed Attempt 1

My first attempt to fix it was to move the defaultOptions from the root level to the meta level. But then TypeScript gives an error:

Argument of type '{ name: string; meta: { type: "layout"; docs: { description: string; recommended: true; requiresTypeChecking: false; }; fixable: "whitespace"; schema: { type: "object"; properties: { maxLength: { type: "number"; description: string; }; }; additionalProperties: false; }[]; defaultOptions: [...]; messages: { ...; }; }...' is not assignable to parameter of type 'Readonly<RuleWithMetaAndName<Options, "incorrectlyFormatted", MyPluginDocs>>'.
  Property 'defaultOptions' is missing in type '{ name: string; meta: { type: "layout"; docs: { description: string; recommended: true; requiresTypeChecking: false; }; fixable: "whitespace"; schema: { type: "object"; properties: { maxLength: { type: "number"; description: string; }; }; additionalProperties: false; }[]; defaultOptions: [...]; messages: { ...; }; }...' but required in type 'Readonly<RuleWithMetaAndName<Options, "incorrectlyFormatted", MyPluginDocs>>'.

Essentially, this is because the createRule helper function uses ESLintUtils.RuleCreator. And that expects all ESLint plugins to have defaultOptions as a mandatory property.

Failed Attempt 2

Duplicating the same default options in two places would violate DRY. So I tried to just move it to a variable:

const defaultOptions = [
  {
    someOption: 100,
  },
] satisfies Options;

export const myRule = createRule<Options, MessageIds>({
  name: "my-rule",
  meta: {
    // [snip]
    defaultOptions,
  },
  // [snip]
  defaultOptions
});

But that still fails the rule because it is not type aware:

Default options must be an array.

Questions

  1. If I want to have the "most correct" ESLint plugin, should I have defaultOptions ONLY at the root level, ONLY at the meta level, or BOTH? I did take a look at the documentation for the rule, but it does not discuss this at all!
  2. Is it a bug that defaultOptions is a required field for the purposes of ESLintUtils.RuleCreator? Should I submit a pull request to fix that?
  3. Should we update the rule to become type aware? I took a brief look at the source code and it seems like none of the rules in eslint-plugin-eslint-plugin are type aware. So I guess doing this would mean pulling in typescript-eslint as a dependency. Would that be on the table?

CC: @JoshuaKGoldberg (sorry for the direct ping, but I think this is in your wheelhouse, and feel free to assign me some work on updating code/docs in typescript-eslint based on the resolution of this)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions