diff --git a/.vscode/settings.json b/.vscode/settings.json index 9c316d5..e217b26 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,7 @@ "ints", "pubspec", "redeclares", + "RGBO", "subosito", "Supertypes", "tearoffs", diff --git a/packages/altive_lints/lib/altive_lints.dart b/packages/altive_lints/lib/altive_lints.dart index 60e98bd..25b79c4 100644 --- a/packages/altive_lints/lib/altive_lints.dart +++ b/packages/altive_lints/lib/altive_lints.dart @@ -1,5 +1,6 @@ import 'package:custom_lint_builder/custom_lint_builder.dart'; +import 'src/lints/avoid_hardcoded_color.dart'; import 'src/lints/avoid_hardcoded_japanese.dart'; import 'src/lints/avoid_shrink_wrap_in_list_view.dart'; import 'src/lints/avoid_single_child.dart'; @@ -10,6 +11,7 @@ PluginBase createPlugin() => _AltivePlugin(); class _AltivePlugin extends PluginBase { @override List getLintRules(CustomLintConfigs configs) => [ + const AvoidHardcodedColor(), const AvoidHardcodedJapanese(), const AvoidShrinkWrapInListView(), const AvoidSingleChild(), diff --git a/packages/altive_lints/lib/src/lints/avoid_hardcoded_color.dart b/packages/altive_lints/lib/src/lints/avoid_hardcoded_color.dart new file mode 100644 index 0000000..2119151 --- /dev/null +++ b/packages/altive_lints/lib/src/lints/avoid_hardcoded_color.dart @@ -0,0 +1,78 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/type.dart'; +import 'package:analyzer/error/listener.dart'; +import 'package:custom_lint_builder/custom_lint_builder.dart'; + +/// An `avoid_hardcoded_color` rule that discourages the use of +/// hardcoded colors directly in the code, promoting the use of `ColorScheme`, +/// `ThemeExtension`, or other Theme-based systems for defining colors. +/// +/// This practice ensures that colors are consistent and +/// adaptable to different themes and accessibility settings. +/// +/// ### Example +/// +/// #### BAD: +/// +/// ```dart +/// Container( +/// color: Color(0xFF00FF00), // LINT +/// ); +/// ``` +/// +/// #### GOOD: +/// +/// ```dart +/// Container( +/// color: Theme.of(context).colorScheme.primary, +/// ); +/// ``` +class AvoidHardcodedColor extends DartLintRule { + const AvoidHardcodedColor() : super(code: _lintCode); + + static const _lintCode = LintCode( + name: 'avoid_hardcoded_color', + problemMessage: 'Avoid using hardcoded color. Use ColorScheme, ' + 'ThemeExtension, or other Theme-based color definitions instead. ' + 'Consider using Theme.of(context).colorScheme or a custom ' + 'ThemeExtension for color definitions.', + ); + + @override + void run( + CustomLintResolver resolver, + ErrorReporter reporter, + CustomLintContext context, + ) { + context.registry.addInstanceCreationExpression((node) { + final typeName = + node.staticType?.getDisplayString(withNullability: false); + + if (typeName == 'Color') { + reporter.reportErrorForNode(code, node); + } + }); + + context.registry.addPrefixedIdentifier((node) { + final prefix = node.prefix.name; + if (prefix == 'Colors') { + final element = node.staticElement; + if (element is PropertyAccessorElement) { + final returnType = element.returnType; + if (_isColorType(returnType)) { + reporter.reportErrorForNode(code, node); + } + } + } + }); + } + + bool _isColorType(DartType? type) { + return type != null && + (type.isDartCoreInt || + type.getDisplayString(withNullability: false) == 'Color' || + type.getDisplayString(withNullability: false) == 'MaterialColor' || + type.getDisplayString(withNullability: false) == + 'MaterialAccentColor'); + } +} diff --git a/packages/altive_lints/lint_test/lints/avoid_hardcoded_color.dart b/packages/altive_lints/lint_test/lints/avoid_hardcoded_color.dart new file mode 100644 index 0000000..53b1a00 --- /dev/null +++ b/packages/altive_lints/lint_test/lints/avoid_hardcoded_color.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +class MyWidget extends StatelessWidget { + const MyWidget({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + // expect_lint: avoid_hardcoded_color + const ColoredBox(color: Color(0xFF00FF00)), + // expect_lint: avoid_hardcoded_color + const ColoredBox(color: Color.fromRGBO(0, 255, 0, 1)), + // expect_lint: avoid_hardcoded_color + const ColoredBox(color: Colors.green), + ColoredBox(color: Theme.of(context).colorScheme.primary), + ], + ); + } +}