{"id":10843,"library":"eslint-rule-composer","title":"ESLint Rule Composer","description":"ESLint Rule Composer is a utility library designed to facilitate the creation and modification of ESLint rules by composing them from existing ones. Currently at version 0.3.0, it allows developers to `filterReports`, `mapReports`, or `joinReports` from one or more base rules, enabling highly customized linting behavior without needing to rewrite entire rule definitions. This approach is particularly useful for adding exceptions to existing rules (e.g., ignoring specific patterns in `no-unused-expressions`) or combining the logic of multiple rules. Its primary differentiator is the programmatic manipulation of reported problems and rule definitions, offering a flexible layer over ESLint's core rule API. Given its 0.x.y version, API stability might still be evolving, and its release cadence is likely slow or on-demand, as the last update on NPM was in April 2018.","status":"maintenance","version":"0.3.0","language":"javascript","source_language":"en","source_url":"https://github.com/not-an-aardvark/eslint-rule-composer","tags":["javascript","eslint"],"install":[{"cmd":"npm install eslint-rule-composer","lang":"bash","label":"npm"},{"cmd":"yarn add eslint-rule-composer","lang":"bash","label":"yarn"},{"cmd":"pnpm add eslint-rule-composer","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Runtime peer dependency for accessing core ESLint functionality like Linter and rules. While not explicitly listed as a peerDependency in the provided metadata, it's essential for operation.","package":"eslint","optional":false}],"imports":[{"note":"The package currently primarily supports CommonJS `require()` syntax. There is no official ESM export or guidance for `import` statements in the documentation. Compatibility with older Node.js versions (>=4.0.0) suggests CJS-first design.","wrong":"import ruleComposer from 'eslint-rule-composer';","symbol":"ruleComposer","correct":"const ruleComposer = require('eslint-rule-composer');"},{"note":"When using `eslint-rule-composer`, you typically need to access ESLint's core `Linter` to get references to built-in rules. Ensure `eslint` is installed in your project.","symbol":"Linter","correct":"const { Linter } = require('eslint');"}],"quickstart":{"code":"const ruleComposer = require('eslint-rule-composer');\nconst { Linter } = require('eslint');\n\n// Instantiate ESLint's Linter to get access to core rules\nconst linter = new Linter();\nconst noUnusedExpressionsRule = linter.getRules().get('no-unused-expressions');\n\n// Create a modified version of 'no-unused-expressions' that ignores lines starting with 'expect'\nmodule.exports = ruleComposer.filterReports(\n  noUnusedExpressionsRule,\n  (problem, metadata) => {\n    // Ensure the problem node and its first token exist before accessing properties\n    if (!problem.node || !metadata.sourceCode || !metadata.sourceCode.getFirstToken(problem.node)) {\n      return true; // Keep the report if parsing issue or no token\n    }\n    return metadata.sourceCode.getFirstToken(problem.node).value !== 'expect';\n  }\n);\n\n/* To use this rule:\n  1. Save this code as a rule file (e.g., `rules/custom-no-unused-expressions.js`)\n  2. In your `.eslintrc.js` or equivalent config, define a plugin:\n     module.exports = {\n       plugins: {\n         'my-plugin': {\n           rules: {\n             'custom-no-unused-expressions': require('./rules/custom-no-unused-expressions'),\n           },\n         },\n       },\n       rules: {\n         'my-plugin/custom-no-unused-expressions': 'error',\n       },\n     };\n*/","lang":"javascript","description":"This example demonstrates how to create a custom ESLint rule using `eslint-rule-composer` to modify the behavior of an existing core rule, specifically `no-unused-expressions`, to ignore specific patterns. It also shows the necessary setup for integrating the composed rule into an ESLint configuration."},"warnings":[{"fix":"Pin the exact version (e.g., `\"eslint-rule-composer\": \"0.3.0\"`) in `package.json` to prevent unexpected breaking changes on update, or implement robust integration tests for your custom rules.","message":"The package is currently in version 0.x.y. According to semantic versioning, minor versions (`0.y.z`) can introduce breaking API changes without a major version increment. Developers should pin exact versions or thoroughly test upgrades.","severity":"breaking","affected_versions":">=0.1.0"},{"fix":"Test your custom rules against the specific `eslint` version(s) used in your project. Refer to ESLint's release notes for any breaking changes in its public API or internal structures.","message":"Compatibility with `eslint` versions is not explicitly guaranteed. Changes in ESLint's internal `Linter` API or AST structures across major `eslint` versions could potentially break rules composed with `eslint-rule-composer`.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Always implement defensive checks when accessing rule options. For example, `const whitelist = metadata.options?.[0]?.whitelist || [];` to safely access properties and provide fallbacks.","message":"When accessing rule options via `metadata.options`, directly indexing `metadata.options[0]` can lead to runtime errors if options are not provided or are malformed in the ESLint configuration. `metadata.options` could be `undefined` or an empty array.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"For CommonJS-based projects or older `.eslintrc.js` configurations, `require()` works as shown. For modern ESLint flat configs (`eslint.config.js`) or ESM projects, you might need to wrap `require()` or use a transpilation step if direct `import` is not supported.","message":"The package uses CommonJS `require()`. Integrating it into an ESM-only project or an `eslint.config.js` using flat config (which often implies ESM) might require specific setup (e.g., using `createRequire` or dynamic `import()`) or might not be directly compatible.","severity":"gotcha","affected_versions":"<=0.3.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure `const ruleComposer = require('eslint-rule-composer');` is used and the package is correctly installed. Double-check the path if it's a local file.","cause":"The `eslint-rule-composer` module was not correctly imported or `require`d, or it returned an unexpected value.","error":"TypeError: ruleComposer.filterReports is not a function"},{"fix":"Verify that `const { Linter } = require('eslint');` is correctly used and `const linter = new Linter();` is called before accessing `linter.getRules()`.","cause":"The `eslint.Linter` object was not correctly instantiated or imported, or the `eslint` package itself is not installed or compatible.","error":"TypeError: Cannot read properties of undefined (reading 'getRules')"},{"fix":"Add defensive coding for accessing rule options: `const whitelist = metadata.options?.[0]?.whitelist || [];` to safely handle cases where options might not be provided in the ESLint configuration.","cause":"Attempted to access a property (e.g., `whitelist`) from `metadata.options[0]` when `metadata.options` or `metadata.options[0]` was `undefined` or `null`.","error":"TypeError: Cannot read properties of undefined (reading 'whitelist')"}],"ecosystem":"npm"}