Skip to content

kaliberjs/eslint-plugin

Repository files navigation

@kaliber/eslint-plugin

Opinionated ESLint plugin enforcing Kaliber's code conventions. Bundles custom rules, curated third-party rules, and formatting conventions into a single shareable configuration.

Usage

Create an eslint.config.js file in your project root:

const kaliberConfig = require('@kaliber/eslint-plugin/eslint.config')

module.exports = [
  ...kaliberConfig,
  // your project-specific overrides here
]

Custom rules

Rule Description
component-properties Destructure component props, use spread passing for same-name props, and avoid passing state setters as props
layout-class-name Components are black boxes — use layoutClassName for positioning instead of className
naming-policy Enforce naming conventions for components, CSS files, CSS variables, root class names, and refs
no-default-export Prefer named exports over default exports — except in App, template, and page files
no-relative-parent-import Disallow ../ imports — use root-slash imports that survive file moves
import-sort Enforce grouped and ordered import statements with auto-fix support
jsx-key Require key prop in iterators but allow keyless JSX in array-literal DSL patterns
position-center Avoid place-content: center — it only aligns tracks and often does nothing
todo-ticket-reference Require TODO comments to reference a Jira ticket

Tracking rules (data-x)

Rule Description
data-x-required Every <a> and <button> must have a data-x tracking attribute
data-x-context Elements with data-x must also include data-x-context to identify page location
data-x-latin-only data-x values must use ASCII characters only — no accented or non-Latin characters
data-x-clickout-prefix External links (http/https) must use the clickout- prefix in data-x
data-x-cta-prefix Call-to-action <a> elements must use the cta- prefix in data-x
data-x-toggle-prefix Toggle/accordion elements must use the toggle- prefix in data-x
data-x-onpage-action-format On-page actions must follow the action-target format (e.g. scroll-applyform, open-modal)
data-x-unique-id Repeated elements with the same data-x must include data-x-id for disambiguation
data-x-sectioning-elements Sectioning HTML elements (section, header, footer, nav, etc.) must have data-x
data-x-form-naming Form elements must have a data-x value ending with -form

Documentation

Each rule is self-contained — implementation, tests, and documentation live together:

rules/naming-policy/
  index.js     ← rule implementation
  test.js      ← rule tests
  readme.md    ← rule documentation

The docsUrl helper resolves the readme.md from the rule's __dirname:

Each rule exposes two pieces of metadata via meta.docs:

  • description — a one-liner explaining what the rule enforces. This is the primary context for both editor tooltips and AI coding assistants. LLMs that parse ESLint output see this inline without needing to follow any link.
  • url — a file:// URL pointing to the full documentation on disk. It resolves locally regardless of where the package is installed (source checkout or node_modules), so it works without network access or GitHub authentication.

This makes rule violations self-documenting: a developer hovering over an error in VS Code sees the description and a clickable link to the full explanation. An LLM assisting with code sees the description in the lint output and can read the referenced file for deeper context on why the rule exists and how to fix violations.

Adding documentation for a new rule

  1. Create rules/{rule-name}/readme.md
  2. In the rule's index.js, add:
    const docsUrl = require('../../machinery/docsUrl')
    
    module.exports = {
      meta: {
        type: 'problem',
        docs: {
          description: 'One-line description of the rule',
          url: docsUrl(__dirname),
        },
      },
      // ...
    }

Migrating from legacy config

If your project still uses a legacy .eslintrc file, you can automatically migrate to the flat config format:

Change package.json

Update the lint script in your package.json — the new flat config picks up eslint.config.js automatically, and .gitignore is used as the ignore file:

"lint.javascript": "eslint"

Was:

"lint.javascript": "eslint -c .eslintrc --ignore-path .gitignore './**/*.js'"

Run the migration script

# In your project directory:
npx kaliber-eslint-migrate

# Preview without writing any files:
npx kaliber-eslint-migrate --dry-run

# Print the generated config to stdout:
npx kaliber-eslint-migrate --stdout

# Overwrite an existing eslint.config.js:
npx kaliber-eslint-migrate --force

The migration script will:

  • Rename deprecated rules (e.g. no-native-reassignno-global-assign)
  • Move stylistic rules to the @stylistic namespace
  • Remap import/ rules to import-x/
  • Remove rules with no ESLint v9 replacement
  • Diff your rules against the shared Kaliber config and only keep project-specific overrides
  • Preserve custom globals and ignorePatterns

Globals

Instead of depending on the globals npm package, this plugin uses an inlined machinery/globals.json containing only the environments we need (browser, node, jest).

Publishing

>> yarn publish
>> git push
>> git push --tags

About

Enforces Kaliber's code conventions, helping maintain consistency across projects

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors