new-rule | Skill Performance & Reviews | TopRankSkills

TopRank Skills

Home / Skills / development / new-rule

new-rule

maintained by SonarSource

star 1.2k account_tree 192 verified_user MIT License
bolt View GitHub

name: new-rule description: Implement a new SonarJS rule from scratch. Use when creating a new rule, scaffolding rule files, or understanding the full rule implementation workflow. disable-model-invocation: true

Overview

New rules follow the pattern: RSPEC description → scaffold → implement → test → ruling.

Step 1: Scaffold the Rule

npm run new-rule

This interactive script generates in packages/jsts/src/rules/SXXXX/:

  • index.ts — rule export
  • rule.ts — ESLint rule implementation (skeleton)
  • cb.fixture.js — empty comment-based test fixture
  • cb.test.js — test launcher

It also auto-generates (not tracked by git):

  • Java check class SXXXX.java
  • Updates rules/rules.ts and rules/plugin-rules.ts
  • Updates AllRules.java

Step 2: Configure the Java Check Class

In the generated Java class, verify:

  • @JavaScriptRule and/or @TypeScriptRule annotations match target languages
  • If rule has options, override configurations() method (see /rule-options skill)
  • If rule targets test files, extend TestFileCheck instead of Check

Step 3: Implement the Rule

File Structure

File Purpose
rule.ts ESLint rule implementation
meta.ts Manual metadata: implementation, eslintId, schema, re-exports fields
config.ts Option definitions with fields array (if rule has options)
generated-meta.ts Auto-generated from RSPEC — do not edit

Rule Template

import { generateMeta } from '../helpers/index.js';
import { meta } from './meta.js';

const messages = {
  errorKey: 'Error message to display',
};

export const rule: Rule.RuleModule = {
  meta: generateMeta(meta, { messages }),
  create(context: Rule.RuleContext) {
    return {
      Identifier(node: estree.Identifier) {
        if (/* violation detected */) {
          context.report({ messageId: 'errorKey', node });
        }
      },
    };
  },
};

Be Conservative

Never report when uncertain. False positives are worse than missed detections.

const services = context.sourceCode.parserServices;
if (!isRequiredParserServices(services)) {
  return; // No type info — don't report
}

When in doubt: skip.

Step 4: Check Shared Helpers

Before writing any utility code, check packages/jsts/src/rules/helpers/:

File Contains
ast.ts isFunctionNode, isIdentifier, hasTypePredicateReturn, AST traversal
module.ts isESModule, getImportDeclarations, getFullyQualifiedName
package-jsons/dependencies.ts getDependencies, getReactVersion
index.ts Re-exports all helpers — check here first

If a new utility would benefit multiple rules, add it to the appropriate helper file.

Step 5: Generate Metadata

After setting up meta.ts and optionally config.ts:

npm run generate-meta

This creates/updates generated-meta.ts with defaultOptions, sonarKey, scope, languages.

Step 6: Write Tests

See /test-rule skill for full testing documentation.

Quick start — write cb.fixture.js:

someCleanCode();                            // no issue raised

someFaultyCode(); // Noncompliant {{message}}
//  ^^^^^^^^^^

Run:

npx tsx --test packages/jsts/src/rules/S1234/**/*.test.ts

Step 7: Run Ruling

See /ruling skill. Required before merging new or modified rules.

Rule Implementation Patterns

Wrapping an ESLint Rule (decorated)

// meta.ts
export const implementation = 'decorated';
export const eslintId = 'no-magic-numbers';
export const externalRules = [
  { externalPlugin: 'typescript-eslint', externalRule: 'no-magic-numbers' },
];
export * from './config.js';

Original Rule

// meta.ts
export const implementation = 'original';
export const eslintId = 'function-name';
export * from './config.js';
import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema';
export const schema = {
  type: 'array',
  items: [{ type: 'object', properties: { format: { type: 'string' } } }],
} as const satisfies JSONSchema4;

RSPEC Tags

When creating the RSPEC PR:

  • Tag type-dependent if the rule uses TypeScript type information
  • Add dependencies field if rule requires a specific import (e.g., 'react', 'jest')
  • Add compatibleLanguages: ['js', 'ts'] as appropriate

References

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!

Skill Details

GitHub Stars 1.2k
GitHub Forks 192
Created Mar 2026
Last Updated 3个月前
development development architecture patterns

Related Skills

dagger-design-proposals
chevron_right
nestjs-expert
chevron_right
docker-expert
chevron_right
kafka-streams-topology
chevron_right
kafka-architecture
chevron_right

Build your own?

Join 12,000+ developers contributing to the Claude ecosystem.