with one click
new-rule
// Implement a new SonarJS rule from scratch. Use when creating a new rule, scaffolding rule files, or understanding the full rule implementation workflow.
// Implement a new SonarJS rule from scratch. Use when creating a new rule, scaffolding rule files, or understanding the full rule implementation workflow.
Use before a SonarJS release or when the Peach Main Analysis workflow on SonarSource/peachee-js shows failed jobs or suspicious project issue-count drops that need triage. Classify failed Peach jobs and flag likely project-configuration regressions using docs/peach-main-analysis.md.
Use before a SonarJS release or when the Peach Main Analysis workflow on SonarSource/peachee-js shows failed jobs or suspicious project issue-count drops that need triage. Classify failed Peach jobs and flag likely project-configuration regressions using docs/peach-main-analysis.md.
Provides guidance on implementing and fixing SonarJS rules. Use also when tracing false positives, working with rule configuration, or understanding native vs external rule implementations.
Add or modify rule options in SonarJS, including the fields array, SonarQube UI visibility, and Java check class configuration. Use when working on rule configurations.
Provides test quality standards and best practices. Use when writing test cases, creating unit tests, implementing tests, or refining/reviewing test code. Essential for test generation and test refinement phases.
Build pipeline for SonarJS. Use when asked to build the project, regenerate metadata, understand the build pipeline, or run npm build scripts.
| 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 |
New rules follow the pattern: RSPEC description → scaffold → implement → test → ruling.
npm run new-rule
This interactive script generates in packages/analysis/src/jsts/rules/SXXXX/:
index.ts — rule exportrule.ts — ESLint rule implementation (skeleton)cb.fixture.js — empty comment-based test fixturecb.test.js — test launcherIt also auto-generates (not tracked by git):
SXXXX.javarules/rules.ts and rules/plugin-rules.tsAllRules.javaIn the generated Java class, verify:
@JavaScriptRule and/or @TypeScriptRule annotations match target languagesconfigurations() method (see /rule-options skill)TestFileCheck instead of Check| 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 |
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 });
}
},
};
},
};
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.
Before writing any utility code, check packages/analysis/src/jsts/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.
After setting up meta.ts and optionally config.ts:
npm run generate-meta
This creates/updates generated-meta.ts with defaultOptions, sonarKey, scope, languages.
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/analysis/src/jsts/rules/S1234/**/*.test.ts
See /ruling skill. Required before merging new or modified rules.
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';
// 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;
When creating the RSPEC PR:
type-dependent if the rule uses TypeScript type informationdependencies field if rule requires a specific import (e.g., 'react', 'jest')compatibleLanguages: ['js', 'ts'] as appropriate