new-lint
Creates a new lint rule with quick fix and tests for the many_lints package. Use when the user wants to add a new lint rule.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Creates a new lint rule with quick fix and tests for the many_lints package. Use when the user wants to add a new lint rule.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | new-lint |
| description | Creates a new lint rule with quick fix and tests for the many_lints package. Use when the user wants to add a new lint rule. |
You are creating a new lint rule for the many_lints Dart linter package. The user will provide context describing what the lint should detect, possibly a lint name, and optionally reference links.
Extract from the $ARGUMENTS:
Before writing any code:
📖 ALWAYS START HERE: Read the Lint Rule Cookbooks (in this directory)
Read these reference docs to understand the framework:
Read any reference links the user provided in $ARGUMENTS.
If the cookbook doesn't cover your specific pattern, read 1-2 existing rules in lib/src/rules/ and their corresponding fixes in lib/src/fixes/ and tests in test/ to understand the codebase patterns. Pick rules that are most similar to the new lint being created.
Read lib/src/type_checker.dart and lib/src/ast_node_analysis.dart for reusable utilities.
Before implementing, use AskUserQuestion to clarify:
Only ask questions that aren't already answered by the user's input.
Create lib/src/rules/<lint_name>.dart following this exact pattern:
import 'package:analyzer/analysis_rule/analysis_rule.dart';
import 'package:analyzer/analysis_rule/rule_context.dart';
import 'package:analyzer/analysis_rule/rule_visitor_registry.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/error/error.dart';
// Add if needed:
// import 'package:many_lints/src/type_checker.dart';
// import 'package:many_lints/src/ast_node_analysis.dart';
/// <doc comment describing what the rule does>
class <RuleClass> extends AnalysisRule {
static const LintCode code = LintCode(
'<lint_name>',
'<problem message describing what is wrong>',
// Optional: correctionMessage: '<suggestion for how to fix>',
);
<RuleClass>()
: super(
name: '<lint_name>',
description: '<short description>',
);
@override
LintCode get diagnosticCode => code;
@override
void registerNodeProcessors(RuleVisitorRegistry registry, RuleContext context) {
final visitor = _Visitor(this);
// Register for the appropriate AST node type, e.g.:
// registry.addInstanceCreationExpression(this, visitor);
// registry.addClassDeclaration(this, visitor);
// registry.addMethodInvocation(this, visitor);
}
}
class _Visitor extends SimpleAstVisitor<void> {
final <RuleClass> rule;
_Visitor(this.rule);
// Use TypeChecker for type checks:
// static const _checker = TypeChecker.fromName('WidgetName', packageName: 'flutter');
@override
void visit<NodeType>(<NodeType> node) {
// Detection logic here
// Report with: rule.reportAtNode(node) or rule.reportAtToken(node.name)
}
}
Key conventions:
use_cubit_suffix -> UseCubitSuffix)TypeChecker.fromName() or TypeChecker.fromUrl() for type checkslib/src/ast_node_analysis.dart when applicable📖 Consult the Quick Fix Cookbook: See fixes-cookbook.md for comprehensive patterns and examples.
Create lib/src/fixes/<lint_name>_fix.dart following this exact pattern:
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
import 'package:analysis_server_plugin/edit/dart/dart_fix_kind_priority.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
/// Fix that <description of what the fix does>.
class <FixClass> extends ResolvedCorrectionProducer {
static const _fixKind = FixKind(
'many_lints.fix.<lintNameCamelCase>',
DartFixKindPriority.standard,
'<Short description of the fix action>',
);
<FixClass>({required super.context});
@override
CorrectionApplicability get applicability => CorrectionApplicability.singleLocation;
@override
FixKind get fixKind => _fixKind;
@override
Future<void> compute(ChangeBuilder builder) async {
// Access the reported node:
final targetNode = node;
// Navigate to the relevant AST node
// Apply fix using builder.addDartFileEdit(file, (builder) { ... });
}
}
Key conventions:
Fix suffix (e.g., PreferCenterOverAlignFix)many_lints.fix.<lintNameInCamelCase>range.node() for replacing nodes, range.nodeInList() for removing from argument listsaddSimpleReplacement() for simple text replacementsaddDeletion() for removing codeEdit lib/many_lints.dart:
registry.registerWarningRule(<RuleClass>()); in the rules sectionregistry.registerFixForRule(<RuleClass>.code, <FixClass>.new); in the fixes sectionCreate test/<lint_name>_test.dart following this exact pattern:
import 'package:analyzer_testing/analysis_rule/analysis_rule.dart';
import 'package:many_lints/src/rules/<lint_name>.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
void main() {
defineReflectiveSuite(() => defineReflectiveTests(<RuleClass>Test));
}
@reflectiveTest
class <RuleClass>Test extends AnalysisRuleTest {
@override
void setUp() {
rule = <RuleClass>();
// Mock external packages if needed:
// newPackage('package_name').addFile('lib/file.dart', r'''
// class SomeClass {}
// ''');
super.setUp();
}
// Test cases that SHOULD trigger the lint:
Future<void> test_<descriptive_case_name>() async {
await assertDiagnostics(
r'''
<code that should trigger the lint>
''',
[lint(<offset>, <length>)],
);
}
// Test cases that should NOT trigger the lint:
Future<void> test_<descriptive_valid_case>() async {
await assertNoDiagnostics(r'''
<code that should not trigger the lint>
''');
}
}
Key conventions:
<RuleClass>TestassertDiagnostics(code, [lint(offset, length)]) for code that triggers the lintassertNoDiagnostics(code) for code that should NOT trigger the lintnewPackage('name').addFile() to mock external package dependencieslint(offset, length) — offset is the character position, length is the length of the reported node/tokentest_ and use camelCase🚨 CRITICAL: If you discovered or researched any new patterns, you MUST update the cookbooks before completing this task.
You must update if you:
How to update (two places):
Full details — Add to the appropriate cookbook file in this directory:
Brief mention — Add a short entry to the lean quick reference at lib/src/rules/AGENTS.md (or lib/src/fixes/AGENTS.md for fix patterns)
This keeps the cookbooks as living documents that improve with each new rule!
Create docs/src/content/docs/docs/rules/<category>/<lint-name>.md for the new rule.
Determine the category by matching the lint's domain to one of the existing sidebar categories:
class-naming — Suffix/naming rules for classes (Bloc, Cubit, Notifier, etc.)bloc-riverpod — Bloc/Riverpod architecture rulesriverpod-state — Riverpod state/ref usage rulesasync-safety — Async/await safety ruleswidget-best-practices — Widget usage best practiceswidget-replacement — Prefer simpler/more specific widgetsstate-management — StatefulWidget/setState rulescontrol-flow — Control flow, cascades, exceptions, switchescollection-type — Collection/Iterable/Map rulespattern-matching — Dart pattern matching rulestype-annotations — Type annotation preferencescode-organization — Code structure and organizationshorthand-patterns — Shorthand/constructor sugarhook-rules — Flutter Hooks rulestesting-rules — Test-related rulesresource-management — Disposal, listeners, subscriptionscode-quality — General code qualityIf no existing category fits, create a new directory AND add a matching autogenerate entry in docs/astro.config.mjs sidebar config.
Use this template (match the format of existing pages):
---
title: <lint_name>
description: "<Short description>"
sidebar:
badge:
text: "Fix"
variant: "tip"
label: <lint_name>
---
<span class="rule-badge rule-badge--version">vX.Y.Z</span>
<span class="rule-badge rule-badge--warning">Warning</span>
<span class="rule-badge rule-badge--fix">Fix</span>
<span class="rule-badge rule-badge--category"><Category Name></span>
<2-3 sentence human-friendly description of what the lint detects and why it matters.>
## Why use this rule
<Real-world context explaining why this pattern is problematic. Include "See also" links to relevant official docs.>
**See also:** [Link](url) | [Link](url)
## Don't
```dart
// Bad example with comment explaining why it's wrong
<code that triggers the lint>
// Good example
<correct code>
To disable this rule:
plugins:
many_lints:
diagnostics:
<lint_name>: false
Key notes:
- Omit the `sidebar.badge` block entirely if the lint has **no quick fix**
- Omit the `<span class="rule-badge rule-badge--fix">Fix</span>` badge if there is no fix
- Determine the version tag: check the latest version in `pubspec.yaml` — if this is a new unreleased rule, use the next version that will be released
- Use the lint name with underscores (snake_case) for `title` and `label`
- Use dashes (kebab-case) for the filename (e.g., `prefer-center-over-align.md`)
## Step 10: Create an example file
Create `example/lib/<lint_name>_example.dart` to demonstrate the lint rule. Look at existing example files in `example/lib/` for the pattern.
The example file should include:
- A file-level `// ignore_for_file: unused_local_variable` (or similar) to suppress unrelated warnings
- A comment header with the lint name and brief description
- **Bad examples** (code that triggers the lint) with `// LINT:` comments explaining each case
- **Good examples** (correct code that does NOT trigger the lint)
- **Edge cases** where the lint intentionally does NOT trigger (e.g., when `.from()` is needed for downcasting)
Example structure:
```dart
// ignore_for_file: unused_local_variable
// <lint_name>
//
// Brief description of what the lint detects.
// ❌ Bad: Description of bad pattern
class BadExamples {
void example() {
// LINT: Explanation of why this triggers
final x = badCode();
}
}
// ✅ Good: Description of correct pattern
class GoodExamples {
void example() {
final x = goodCode();
}
}
Run the following commands from the project root to ensure everything works:
dart analyze - Ensure there are no issues at all (errors, warnings, or infos). Fix any that appear before proceeding.dart test - Ensure all tests passIf either command fails or reports issues, fix them and re-run until both are fully clean.