Skip to main content

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.

跳到安装

来源信息

仓库
SonarSource/SonarJS
最近来源活动
2026年9月8日 12:22
检测到的 SKILL.md 语言
英语
星标
1,290
分支
192

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
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 ```bash npm run new-rule ``` This interactive script generates in `packages/analysis/src/jsts/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 `MainFileCheck` ## 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 ```typescript 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. ```typescript 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/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. ## Step 5: Generate Metadata After setting up `meta.ts` and optionally `config.ts`: ```bash 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`: ```javascript someCleanCode(); // no issue raised someFaultyCode(); // Noncompliant {{message}} // ^^^^^^^^^^ ``` Run: ```bash npx tsx --test packages/analysis/src/jsts/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`) ```typescript // 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 ```typescript // 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 - Security Hotspot: [PR #3148](https://github.com/SonarSource/SonarJS/pull/3148) - Rule with quickfix: [PR #3141](https://github.com/SonarSource/SonarJS/pull/3141) - Wrapping ESLint rule: [PR #3134](https://github.com/SonarSource/SonarJS/pull/3134)
在 GitHub 查看