Skip to content

feat(eslint-config-base): fully incorporate eslint-config-airbnb-base - #267

Draft
literat wants to merge 13 commits into
mainfrom
feat/eslint-v9-migrate
Draft

literat wants to merge 13 commits into
mainfrom
feat/eslint-v9-migrate

Conversation

@literat

@literat literat commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Description

ESLint v9's flat config migration (#191, merged in #204) left several packages in an inconsistent state: rule formats weren't normalized across eslint-config-react/typescript/jest, and eslint-config-base never fully absorbed eslint-config-airbnb-base — 37 of its style rules were silently dropped, one rule (no-mixed-operators) had a corrupted value that crashes ESLint v9 outright under strict schema validation, and whitespace.js still depended on the real eslint-config-airbnb-base package through a FlatCompat shim that wasn't even a declared dependency. None of the eslint-config-* packages had any test coverage, so none of this was caught automatically.

This PR normalizes the flat-config format across the affected packages, then makes eslint-config-base a complete, self-contained superset of airbnb-base: restores the missing style rules with airbnb's exact values, fixes the crash-causing rule, and rewrites whitespace.js as a small pure function that derives its rule set directly from the package's own rule files instead of the external package. It also adds the package's first test suite (node --test, matching the pattern already used by stylelint-config), covering the base config's airbnb inheritance and ALMA overrides, legacy.js's ES5/strict-mode behavior, optional.js's extra rules, and whitespace.js's severity-downgrade logic.

Additional context

  • style.js still has ~15 pre-existing no-dupe-keys lint findings (a rule is listed once under the airbnb section and again under the ALMA override section) — valid JS, flagged by the repo's own lint, left as-is pending a decision on whether to clean it up separately.
  • Several restored rules (e.g. indent, no-tabs) are marked deprecated upstream per eslint/eslint#17522 — they still work today but ESLint may drop them in a future major; worth revisiting if/when that happens.

Related issues

Relates to #191

Copilot AI lite review requested due to automatic review settings September 22, 2026 11:46
@github-actions github-actions Bot added the feature New feature or request label Sep 22, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Several rule overrides drop required/meaningful options (changing behavior unexpectedly), and the base legacy config references an invalid node/no-process-env rule ID that can break ESLint config loading.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 High severity · 4 Medium severity

Open (5)
What changed in this PR

This PR completes the ESLint v9 flat-config migration across the repo’s eslint-config-* packages, with a focus on making @alma-oss/eslint-config-base fully self-contained (no longer relying on eslint-config-airbnb-base via FlatCompat) while restoring Airbnb Base rule parity and adding initial automated tests for the base package.

Changes:

  • Rebuilds eslint-config-base as a self-contained flat config by inlining Airbnb Base rules into local rules/* modules and rewriting legacy.js/whitespace.js without FlatCompat.
  • Normalizes/updates config formatting across React/TypeScript/Jest packages (including @eslint/compat usage where still extending external configs).
  • Adds a Node test suite (node --test) for eslint-config-base plus fixtures, and updates repo-level ignore rules for fixtures.
File Description
packages/​eslint-config-typescript/​index.js Spreads TS ESLint recommended flat configs; refines file targeting and parser options.
packages/​eslint-config-react/​whitespace.js Wraps Airbnb whitespace extends with fixupConfigRules.
packages/​eslint-config-react/​rules/​react.js Stops using FlatCompat in rule module; retains local rule overrides.
packages/​eslint-config-react/​rules/​react-hooks.js Stops using FlatCompat in rule module; retains local rule overrides.
packages/​eslint-config-react/​rules/​react-a11y.js Stops using FlatCompat in rule module; retains local rule overrides.
packages/​eslint-config-react/​package.json Adds @eslint/compat dependency.
packages/​eslint-config-react/​index.js Extends Airbnb React rule sets via FlatCompat and merges local overrides.
packages/​eslint-config-jest/​index.js Uses Jest flat configs and extends jest-formatting via FlatCompat.
packages/​eslint-config-base/​whitespace.js Replaces external whitespace shim with derived rule set + downgrade logic.
packages/​eslint-config-base/​rules/​variables.js Restores Airbnb Base variable rules and ALMA overrides.
packages/​eslint-config-base/​rules/​style.js Restores Airbnb Base style rules and ALMA overrides (large expansion).
packages/​eslint-config-base/​rules/​strict.js Adds name metadata for rule module.
packages/​eslint-config-base/​rules/​node.js Restores Airbnb Base Node-related core rules.
packages/​eslint-config-base/​rules/​imports.js Restores Airbnb Base import rules plus ALMA customizations/TS extensions.
packages/​eslint-config-base/​rules/​es6.js Restores Airbnb Base ES6 rules plus ALMA customizations.
packages/​eslint-config-base/​rules/​errors.js Restores Airbnb Base “errors” rules plus ALMA customizations.
packages/​eslint-config-base/​rules/​best-practices.js Restores Airbnb Base best-practices rules plus ALMA customizations.
packages/​eslint-config-base/​package.json Removes airbnb-base/compat deps; adds tests and new dependency.
packages/​eslint-config-base/​optional.js Renames config to @alma-oss/* and adjusts rule set.
packages/​eslint-config-base/​legacy.js Rewrites legacy config without FlatCompat, adds legacy-specific overrides.
packages/​eslint-config-base/​index.js Rewrites base config without FlatCompat, composes local rule modules.
packages/​eslint-config-base/​__tests__/​index.test.js Adds first ESLint-based test suite for base/legacy/optional/whitespace.
packages/​eslint-config-base/​__tests__/​__fixtures__/​valid.js Adds valid-code fixture for base/optional tests.
packages/​eslint-config-base/​__tests__/​__fixtures__/​legacy-valid.js Adds ES5/strict fixture for legacy config tests.
packages/​eslint-config-base/​__tests__/​__fixtures__/​invalid.js Adds intentionally-invalid fixture for rule assertions.
eslint.config.js Ignores fixtures directory to avoid linting invalid test inputs.
.prettierignore Ignores fixtures directory to prevent reformatting invalid test inputs.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +73 to +76
rules: {
// Using process.env is encouraged in configuration files
'node/no-process-env': 'off',
},
import optionalConfig from '../optional.js';
import whitespaceConfig from '../whitespace.js';

const readFixture = (name) => fs.readFileSync(`./__tests__/__fixtures__/${name}`, 'utf-8');
Comment on lines +91 to +96
it('flags additional insights not enabled by the base config', async () => {
const result = await lint([...baseConfig, ...optionalConfig], 'const foo = Symbol();\n\nexport default foo;\n');
const ruleIds = result.messages.map((message) => message.ruleId);

assert.ok(ruleIds.includes('symbol-description'));
});
// Allows omitting braces in arrow functions
// https://eslint.org/docs/rules/arrow-body-style
'arrow-body-style': ['warn', 'as-needed'],
'arrow-body-style': 'warn', // airbnb: 'error'
Comment on lines +670 to +674
'object-curly-newline': 'warn', // airbnb: ['error', {...}]

// ALMA: Downgraded from error to warn
// Require or disallow padding inside curly braces
'object-curly-spacing': 'warn', // airbnb: ['error', 'always']
Copilot AI review requested due to automatic review settings September 22, 2026 11:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

It contains config/test correctness issues (invalid rule key in legacy config, lost arrow-body-style option, and “valid” fixtures that will trigger warnings) that can break consumers and/or fail the new test suite.

Review effort: Lite
Findings: 1 High severity · 4 Medium severity

Open (5)
Previously missed (4)

In code that hasn't changed since last review

Medium severity Remove padded blank lines from the legacy fixture

packages/​eslint-config-base/​__tests__/​__fixtures__/​legacy-valid.js:7

This legacy fixture includes padded blank lines inside the function body, which will trigger padded-blocks and cause the test’s “no warnings” assertion to fail.

Medium severity Remove padded blank lines from the function fixture

packages/​eslint-config-base/​__tests__/​__fixtures__/​valid.js:5

This fixture currently contains padded blank lines inside the function body, which will trigger padded-blocks (configured in the base style rules). The test expects 0 warnings, so the fixture should avoid padding inside blocks.

This issue also appears on line 7 of the same file.

Medium severity Set FlatCompat baseDirectory for package-relative resolution

packages/​eslint-config-react/​index.js:5

FlatCompat defaults to resolving extends/plugins relative to process.cwd(). That can break consumers depending on where ESLint is executed (monorepos, editors, etc.). Set baseDirectory so compat.extends(...) resolves relative to this package.

Medium severity Set baseDirectory for Airbnb config resolution

packages/​eslint-config-react/​whitespace.js:5

Same FlatCompat resolution issue here: without baseDirectory, compat.extends('eslint-config-airbnb/whitespace') is resolved relative to the caller’s working directory rather than this package, which can make the config fragile for consumers.

  * make extends compatible with old Airbnb configs
… entirely

  * get rid of dependency on `eslint-config-airbnb-base` because of unsupported ESLint v9
  * adopt all rules
  * groups array had a duplicate '^' entry and was missing the
    '<<', '>>', '>>>' bitwise operators
  * eslint v9's stricter schema validation throws on the duplicate
    item, making the whole config uninstantiable
  * also restored the '==','!=','===','!==' and '&&','||' groups
    that airbnb-base defines but were missing entirely
  * 37 style.js rules existed in eslint-config-airbnb-base but were
    silently dropped during the v9 migration, changing behavior for
    anything relying on full airbnb parity
  * restored them with airbnb's exact values, including
    deprecated-but-functional formatting rules like indent and
    no-tabs, per the decision to keep eslint-config-base a faithful
    superset rather than pre-emptively deferring to prettier
  * whitespace.js depended on FlatCompat + the real
    eslint-config-airbnb-base package via @eslint/eslintrc, which
    wasn't a declared dependency anywhere and only resolved by
    accident through hoisting
  * replaced it with a small pure function that derives the same
    error-only-on-whitespace-rules transform directly from our own
    rule files, so it can never drift from the rest of the config
    and needs no external deps or legacy compat shims
…and whitespace configs

  * none of the eslint-config-* packages had any tests, so a rule
    regression (like the no-mixed-operators crash found earlier)
    could ship silently
  * covers all four entry points: the base config's airbnb
    inheritance and ALMA overrides, legacy's ES5/strict-mode
    requirement, optional's extra rules, and whitespace's
    error-only-on-whitespace-rules transform
  * added a 'test' script so lerna run test actually picks the
    package up
  * the new fixtures are deliberately invalid/non-standard js, so
    the repo's own strict self-lint flagged them as violations
  * the existing ignores entry couldn't do this globally because it
    shared an object with rules/settings, which in flat config only
    scopes that config's own rules rather than excluding files
    repo-wide - added a standalone ignores-only entry
  * no-multi-str and no-useless-escape were defined in both
    best-practices.js and style.js with identical values, dead
    redundancy left over from restoring the missing style rules
  * airbnb-base itself only defines these two rules in
    best-practices.js, so this wasn't inherited duplication - removed
    the style.js copies and kept best-practices.js as the single
    source of truth
@literat
literat force-pushed the feat/eslint-v9-migrate branch from 52fb825 to 07d1866 Compare September 22, 2026 12:06
'use strict';

return a + b;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think here should not be the empty line

export function sum (a, b) {

return a + b;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Here should not be an empty line

export default {
name: '@alma-oss/eslint-config-base/rules/errors',
rules: {
// Disallow Use of console

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Why is this comment being removed?

// https://eslint.org/docs/rules/no-console
'no-console': 'warn',

// disallow irregular whitespace outside of strings and comments

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Use this comment.

// downgraded to warn for gradual adoption
// allows omitting braces in arrow functions
// https://eslint.org/docs/rules/arrow-body-style
'arrow-body-style': ['warn', 'as-needed'],

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This was correct.

// extended devDependencies patterns to include TypeScript and additional tools
// Forbid the use of extraneous packages
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md
// paths are treated both as absolute paths, and relative to process.cwd()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Use this comment.

Comment thread packages/eslint-config-jest/index.js
// https://eslint.org/docs/rules/no-multi-spaces
'no-multi-spaces': 'warn',

// Disallow reassigning function parameters

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think these comments were valid, only // airbnb error should be removed.


// downgraded to warn and allow short circuits/ternaries
// disallow usage of expressions in statement position
// but allow them in short circuit and ternary expressions

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Valid comment

'arrow-body-style': ['warn', 'as-needed'],
'arrow-body-style': 'warn',

// Require space before/after arrow function's arrow

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Valid comment.

// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md
'import/prefer-default-export': 'off',

// Ensure consistent use of file extension within the import path

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This one was valid

},
],

// Ensures that there is no resolvable path back to this module via its dependencies

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This one was valid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants