>
dart_skills_lint package, expose it as a toggleable CLI flag, and verify its behavior.lib/src/rules/ extending SkillRule.[!TIP] If your rule expects a specific structure in the skill's YAML frontmatter (e.g., insidemetadata), document this structure clearly in the class Dart docstring.
// lib/src/rules/my_new_rule.dart
import '../models/analysis_severity.dart';
import '../models/skill_context.dart';
import '../models/skill_rule.dart';
import '../models/validation_error.dart';
class MyNewRule extends SkillRule {
MyNewRule({super.severity});
@override
Future<List<ValidationError>> validate(SkillContext context) async {
final errors = <ValidationError>[];
// Add validation logic here using context.rawContent or context.directory
return errors;
}
}
context.parsedYaml. @override
Future<List<ValidationError>> validate(SkillContext context) async {
final errors = <ValidationError>[];
final yaml = context.parsedYaml;
if (yaml != null) {
final metadata = yaml['metadata'];
if (metadata is Map) {
// Read your custom config here
}
}
return errors;
}
lib/src/rule_registry.dartCheckType instance to RuleRegistry.allChecks list. This automatically exposes it as a CLI flag.// lib/src/rule_registry.dart in allChecks list
const CheckType(
name: MyNewRule.ruleName,
defaultSeverity: MyNewRule.defaultSeverity,
help: 'Description of what the rule does for CLI help.',
),
RuleRegistry.createRule to instantiate your rule:// lib/src/rule_registry.dart in createRule method
static SkillRule? createRule(String name, AnalysisSeverity severity) {
switch (name) {
// ... other rules
case MyNewRule.ruleName:
return MyNewRule(severity: severity);
default:
return null;
}
}
defaultSeverity: AnalysisSeverity.disabled), passing the flag --check-my-new-rule will automatically enable it with AnalysisSeverity.error severity (handled in entry_point.dart).SkillContext. This is faster and avoids I/O dependencies.// test/my_new_rule_test.dart
import 'dart:io';
import 'package:dart_skills_lint/src/models/analysis_severity.dart';
import 'package:dart_skills_lint/src/models/skill_context.dart';
import 'package:dart_skills_lint/src/models/validation_error.dart';
import 'package:dart_skills_lint/src/rules/my_new_rule.dart';
import 'package:test/test.dart';
void main() {
group('MyNewRule', () {
test('flags invalid content', () async {
final rule = MyNewRule(severity: AnalysisSeverity.warning);
final context = SkillContext(
directory: Directory('dummy'),
rawContent: 'Invalid content',
);
final List<ValidationError> errors = await rule.validate(context);
expect(errors, isNotEmpty);
expect(errors.first.message, contains('Expected error message'));
});
test('passes valid content', () async {
final rule = MyNewRule(severity: AnalysisSeverity.warning);
final context = SkillContext(
directory: Directory('dummy'),
rawContent: 'Valid content',
);
final List<ValidationError> errors = await rule.validate(context);
expect(errors, isEmpty);
});
});
}
popmark), you should use a temporary directory for testing instead of in-memory mocks. late Directory tempDir;
setUp(() async {
tempDir = await Directory.systemTemp.createTemp('my_rule_test.');
});
tearDown(() async {
if (tempDir.existsSync()) {
await tempDir.delete(recursive: true);
}
});
test('flags invalid file content', () async {
final Directory skillDir = await Directory('${tempDir.path}/test-skill').create();
await File('${skillDir.path}/SKILL.md').writeAsString('Invalid content');
final rule = MyNewRule(severity: AnalysisSeverity.warning);
final context = SkillContext(directory: skillDir, rawContent: 'Invalid content');
final List<ValidationError> errors = await rule.validate(context);
expect(errors, isNotEmpty);
});
test/cli_integration_test.dart using TestProcess.[!IMPORTANT] When writing integration tests that use config files andTestProcess, ensure that paths in the config file and paths passed to the CLI match in style (both relative or both absolute) to avoid issues with path matching inentry_point.dart.
README.md:
RULES.md:
rules_md_consistency_test.dart test.documentation/knowledge/SPECIFICATION.md:
lib/src/rules/.lib/src/rule_registry.dart.test/ using in-memory SkillContext.README.md.RULES.md.documentation/knowledge/SPECIFICATION.md (if applicable).dart format . to format code.dart analyze --fatal-infos to ensure no issues.dart test to ensure tests passing.