Skip to content

Deprecated rules do not follow ESLint's DeprecatedInfo type/schema for replacedBy. #2696

@virtuallyunknown

Description

@virtuallyunknown

Hello!

I am authoring a small library where I import multiple eslint plugins (unicorn included) to create my own eslint configuration. As such, I import these libraries and then parse all the rules they export, for example:

import eslintUnicorn from 'eslint-plugin-unicorn';
ruleSchema.parse(eslintUnicorn.rules);

I then store relevant information about them in a database, which lets me keep track of updates between versions and other stuff.

Until recently everything worked, but a recent release broke my schema, which I use to parse every library rule that I read from.

export const baseRuleSchema = z.object({
    // parts skipped for brevity
    deprecated: z.union([
        z.boolean(),
        z.object({
            message: z.string().optional(),
            url: z.string().url().optional(),
            replacedBy: z.union([
                z.array(
                    z.object({
                        message: z.string().optional(),
                        url: z.string().url().optional(),
                    })
                ),
            ]).optional()
        })
    ]).optional().default(false),
});

This is a Zod schema that mimics the structure in which ESLint libraries should export their rules, and in particular the deprecated property.

deprecated: (boolean | DeprecatedInfo) Indicates whether the rule has been deprecated. You may omit the deprecated property if the rule has not been deprecated.

Further, there is a separate page dedicated to DeprecatedInfo and how it should be structured, and how ReplacedByInfo should be structured.

replacedBy (ReplacedByInfo[])
Information about the available replacements for the rule. This may be an empty array to explicitly state there is no replacement.

Now if we take a look at how Unicorn publicly exports a deprecated rule, for example no-instanceof-array:

{
    "meta": {
        "deprecated": {
            "message": "Replaced by `unicorn/no-instanceof-builtins` which covers more cases.",
            "url": "https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v59.0.1/docs/deprecated-rules.md#no-instanceof-array",
            "replacedBy": [
                "unicorn/no-instanceof-builtins"
            ]
        }
    }
}

We can clearly identify the problem. The meta.deprecated.replacedBy property should be defined as an array of objects that follow the ReplacedByInfo type, but instead Unicorn exports this as an array of strings.

Here is the source of this problem:

const deprecatedRules = createDeprecatedRules({
// {ruleId: {message: string, replacedBy: string[]}}
'no-instanceof-array': {
message: 'Replaced by `unicorn/no-instanceof-builtins` which covers more cases.',
replacedBy: ['unicorn/no-instanceof-builtins'],
},
'no-length-as-slice-end': {
message: 'Replaced by `unicorn/no-unnecessary-slice-end` which covers more cases.',
replacedBy: ['unicorn/no-unnecessary-slice-end'],
},
'no-array-push-push': {
message: 'Replaced by `unicorn/prefer-single-call` which covers more cases.',
replacedBy: ['unicorn/prefer-single-call'],
},
});

Would you be kind enough to fix this? And if that's not a possibility or something you're willing do to, please let me know so I adapt my schema to handle this edge-case.

Cheers!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmetaIssues related to the plugin itself

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions