Skip to content

Release: v5.0.0 #566

@azat-io

Description

@azat-io

I think we've accumulated quite a bit of technical debt and it's time to think about releasing a new major version.

I'd like to tell you about some of the plans:

Make code refactoring

We have quite a bit of code in the project at the moment.

The utils folder looks like a mess, there are a lot of functions there that should be scattered into folders.

We have quite a few functions that are easy to get confused about, I would like to have a JSDoc in the project and actively use it.

I would also like to unify the naming of functions.

Migrate to ESLint Vitest Rule Tester

I would like the test code to become visually cleaner and more pleasant.

We will be able to use hooks (beforeEach, beforeAll, afterEach, afterAll). You can run a separate test it.only or skip a test it.skip.

It will be possible to use new Vitest features, such as snapshots.

Create sorting rule func

At the moment we have quite a bit of code duplication.

We have the createESLintRule function in use. We want to think about creating abstraction over abstraction.

But this abstraction must be thin and transparent. We want a lightweight wrapper, not a magic black box.

This is necessary in order not to complicate support and not to deviate too much from the standard ESLint plugins API. So that the project doesn't become difficult to support. “Thick” abstraction will complicate unique cases.

I see the realization roughly like this:

/**
 * Configuration options for creating a sorting rule.
 *
 * @template Options - The options type for the specific sorting rule.
 * @template MessageIds - Union of message IDs used by the rule.
 */
export interface CreateSortingRuleOptions<
  Options extends unknown[],
  MessageIds extends string,
> {
  /**
   * AST node visitors that transform nodes into SortingNode format Each visitor
   * should return an array of SortingNode or null to skip.
   */
  visitors: {
    [K in keyof RuleListener]?: (
      node: Parameters<NonNullable<RuleListener[K]>>[0],
      context: RuleContext<MessageIds, [Options?]>,
      options: Options,
    ) => SortingNode[] | null
  }

  /**
   * Main sorting logic that processes collected nodes.
   *
   * @param nodes - All collected SortingNode instances.
   * @param context - ESLint rule context.
   * @param options - Resolved rule options.
   */
  create(
    nodes: SortingNode[],
    context: RuleContext<MessageIds, [Options?]>,
    options: Options,
  ): void

  /** Rule name as it appears in ESLint configuration. */
  name: ESLintUtils.RuleWithMetaAndName<
    Options,
    MessageIds,
    ESLintPluginDocumentation
  >['name']

  /** ESLint rule metadata. */
  meta: ESLintUtils.RuleWithMetaAndName<
    Options,
    MessageIds,
    ESLintPluginDocumentation
  >['meta']

  /**
   * Optional function to resolve and validate options.
   *
   * @param context - ESLint rule context.
   * @param defaults - Default options.
   * @returns Resolved options.
   */
  resolveOptions?(
    context: RuleContext<MessageIds, [Options?]>,
    defaults: Options,
  ): Options

  /** Default rule options. */
  defaultOptions: Options
}

/**
 * Documentation metadata for ESLint rules.
 *
 * Provides additional information about the rule that can be used by ESLint
 * configurations and documentation generators.
 */
interface ESLintPluginDocumentation {
  /**
   * Indicates whether the rule is part of the recommended configuration. Rules
   * marked as recommended are typically enabled by default in the plugin's
   * recommended preset.
   *
   * @default false
   */
  recommended?: boolean
}

/**
 * Creates an ESLint rule with sorting functionality.
 *
 * @template Options - The options type for the specific sorting rule.
 * @template MessageIds - Union of message IDs used by the rule.
 * @param ruleOptions - Configuration for the sorting rule.
 * @returns ESLint rule object.
 */
export function createSortingRule<
  Options extends unknown[],
  MessageIds extends string,
>(
  ruleOptions: CreateSortingRuleOptions<Options, MessageIds>,
): ReturnType<typeof createEslintRule<[Options?], MessageIds>> {
  let { resolveOptions, defaultOptions, visitors, create, meta, name } =
    ruleOptions

  return createEslintRule<Options, MessageIds>({
    create: context => {
      let settings = getSettings(context.settings)
      let options = complete(context.options[0], settings, defaultOptions)

      /* ... */
    },
    defaultOptions,
    meta,
    name,
  })
}

Remove all deprecated APIs

We have quite a backlog of outdated configuration options.

This adds a lot to the amount of code and causes confusion for people. I would like to get rid of all the old code.

  • Old predefined group names
  • groupKind options
  • Old options like ignorePattern

Make project ESM-only

We are currently building our plugin in CJS. This is a requirement of the old ESLint version. Currently, all LTS versions of Node.js support require(esm), which means we can fully transition to ESM.

To migrate to ESM, we just need to update the build config and add "type": "module" to package.json.

Many ESLint plugins have already completely switched to ESM:

eslint-stylistic/eslint-stylistic#670

eslint-community/eslint-plugin-eslint-plugin#516

And many are planning to:

typescript-eslint/typescript-eslint#11379

vuejs/eslint-plugin-vue#2718

Drop support for Node.js v18.x.x

In April 2025, the end of life of Node.js v18 happened.

I think it's time to drop its support. Not only because of the possibility of switching to ESM, but it will also allow us to use new language features such as toSorted methods.

Besides, as far as I remember, we have already encountered bugs related to Node.js v18.

Drop support legacy ESLint v8.x.x

In September 2024, the end of life of ESLint version 8 happened. It's been 11 months since then. I think we can start thinking about discontinuing support for older versions of ESLint.

I understand that the number of downloads of older versions is still huge and many users still haven't switched to the current version.

But at the same time I think that we can influence the forcing of the update.

At the same time, users who use ESLint v8 are probably not actively updating packages.

It might not be a full drop of support for older versions of the configs. Maybe we will act like eslint-plugin-depend does.

New rules!

I think we should think about creating new rules.

sort-regexp

To develop the rule we will use the default parser, which is used in ESLint: @eslint-community/regexpp.

This rule could sort:

  • capture groups (/(error|warning|info|debug)/)
  • character classes (/[zxa-f0-9A-Z]/)
  • flags (/pattern/igmus)

sort-import-attributes

import wasmModule from './module.wasm' with { type: 'webassembly', credentials: 'include', mode: 'cors' }

import config from './config.json' with { type: 'json' }

Recently, import attributes support has been introduced in Node.js and even browsers.

It is unlikely that this rule will be popular. But I think we should add it anyway.

Do you have any ideas?

If you have any additional ideas, I'd love to hear them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions