-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Added Button assist and two Lints.
- Loading branch information
Showing
11 changed files
with
443 additions
and
6 deletions.
There are no files selected for viewing
70 changes: 70 additions & 0 deletions
70
packages/masamune_lints/lib/buttons/masamune_button_add_icon.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
part of '/masamune_lints.dart'; | ||
|
||
class _MasamuneButtonAddIcon extends DartAssist { | ||
_MasamuneButtonAddIcon(); | ||
|
||
@override | ||
void run( | ||
CustomLintResolver resolver, | ||
ChangeReporter reporter, | ||
CustomLintContext context, | ||
SourceRange target, | ||
) { | ||
context.registry.addInstanceCreationExpression((node) { | ||
if (!target.intersects(node.constructorName.sourceRange)) { | ||
return; | ||
} | ||
final createdType = node.constructorName.type.type; | ||
if (createdType == null || | ||
!TypeChecker.any(_MaterialButtonType.values.map((e) => e.typeChecker)) | ||
.isExactlyType(createdType)) { | ||
return; | ||
} | ||
final simpleIdentifier = node.constructorName.name; | ||
final supportedIdentifier = simpleIdentifier?.toSupportedIdentifier(); | ||
|
||
if (supportedIdentifier != null && supportedIdentifier.hasIcon) { | ||
return; | ||
} | ||
final changeBuilder = reporter.createChangeBuilder( | ||
message: "Add icon to button", | ||
priority: _kAddOrRemoveIconPriority, | ||
); | ||
|
||
changeBuilder.addDartFileEdit((builder) { | ||
if (supportedIdentifier == _SupportedIdentifier.tonal) { | ||
builder.addSimpleReplacement( | ||
node.constructorName.sourceRange, | ||
"FilledButton.tonalIcon", | ||
); | ||
} else { | ||
builder.addSimpleInsertion( | ||
node.constructorName.sourceRange.end, | ||
".icon", | ||
); | ||
} | ||
|
||
bool existIcon = false; | ||
for (var argument in node.argumentList.arguments) { | ||
if (argument is NamedExpression) { | ||
if (argument.name.label.name == "child") { | ||
builder.addSimpleReplacement( | ||
argument.name.sourceRange, | ||
"label:", | ||
); | ||
} | ||
if (argument.name.label.name == "icon") { | ||
existIcon = true; | ||
} | ||
} | ||
} | ||
if (!existIcon) { | ||
builder.addSimpleInsertion( | ||
node.argumentList.arguments.last.sourceRange.end, | ||
", icon: Icon(Icons.add // TODO: Change icon)", | ||
); | ||
} | ||
}); | ||
}); | ||
} | ||
} |
82 changes: 82 additions & 0 deletions
82
packages/masamune_lints/lib/buttons/masamune_button_convert.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
part of '/masamune_lints.dart'; | ||
|
||
class _MasamuneButtonConvert extends DartAssist { | ||
_MasamuneButtonConvert({ | ||
required this.targetType, | ||
}); | ||
final _MaterialButtonType targetType; | ||
late final baseType = targetType != _MaterialButtonType.filled | ||
? targetType.getBaseType() | ||
: null; | ||
|
||
@override | ||
void run( | ||
CustomLintResolver resolver, | ||
ChangeReporter reporter, | ||
CustomLintContext context, | ||
SourceRange target, | ||
) { | ||
context.registry.addInstanceCreationExpression((node) { | ||
if (!target.intersects(node.constructorName.sourceRange)) { | ||
return; | ||
} | ||
|
||
final createdType = node.constructorName.type.type; | ||
if (createdType == null || | ||
!(baseType?.isExactlyType(createdType) ?? false)) { | ||
return; | ||
} | ||
|
||
final simpleIdentifier = node.constructorName.name; | ||
final isFilledButton = const TypeChecker.fromName( | ||
"FilledButton", | ||
packageName: "flutter", | ||
).isExactlyType(createdType); | ||
final supportedIdentifier = simpleIdentifier?.toSupportedIdentifier(); | ||
|
||
if (isFilledButton) { | ||
if (supportedIdentifier?.isTonal ?? false) { | ||
if (targetType == _MaterialButtonType.filledTonal) { | ||
return; | ||
} | ||
} else { | ||
if (targetType == _MaterialButtonType.filled) { | ||
return; | ||
} | ||
} | ||
} | ||
|
||
final changeBuilder = reporter.createChangeBuilder( | ||
message: "Convert to ${targetType.buttonName}", | ||
priority: targetType.priority, | ||
); | ||
|
||
changeBuilder.addDartFileEdit( | ||
(builder) { | ||
builder.addSimpleReplacement( | ||
node.constructorName.sourceRange, | ||
targetType.className + | ||
_getReplacementIdentifier(supportedIdentifier, targetType), | ||
); | ||
}, | ||
); | ||
}); | ||
} | ||
|
||
String _getReplacementIdentifier( | ||
_SupportedIdentifier? identifier, _MaterialButtonType targetType) { | ||
if (identifier?.hasIcon ?? false) { | ||
if (targetType == _MaterialButtonType.filledTonal) { | ||
return ".tonalIcon"; | ||
} else { | ||
return ".icon"; | ||
} | ||
} else { | ||
if (targetType == _MaterialButtonType.filledTonal) { | ||
return ".tonal"; | ||
} else { | ||
return ""; | ||
} | ||
} | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
packages/masamune_lints/lib/buttons/masamune_button_remove_icon.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
part of '/masamune_lints.dart'; | ||
|
||
class _MasamuneButtonRemoveIcon extends DartAssist { | ||
_MasamuneButtonRemoveIcon(); | ||
|
||
@override | ||
void run( | ||
CustomLintResolver resolver, | ||
ChangeReporter reporter, | ||
CustomLintContext context, | ||
SourceRange target, | ||
) { | ||
context.registry.addInstanceCreationExpression((node) { | ||
if (!target.intersects(node.constructorName.sourceRange)) { | ||
return; | ||
} | ||
|
||
final createdType = node.constructorName.type.type; | ||
if (createdType == null || | ||
!TypeChecker.any(_MaterialButtonType.values.map((e) => e.typeChecker)) | ||
.isExactlyType(createdType)) { | ||
return; | ||
} | ||
|
||
final simpleIdentifier = node.constructorName.name; | ||
final supportedIdentifier = simpleIdentifier?.toSupportedIdentifier(); | ||
|
||
if (supportedIdentifier != null && !supportedIdentifier.hasIcon) { | ||
return; | ||
} | ||
|
||
final changeBuilder = reporter.createChangeBuilder( | ||
message: "Remove icon from button", | ||
priority: _kAddOrRemoveIconPriority, | ||
); | ||
|
||
changeBuilder.addDartFileEdit((builder) { | ||
if (supportedIdentifier == _SupportedIdentifier.tonalIcon) { | ||
builder.addSimpleReplacement( | ||
node.constructorName.sourceRange, | ||
"FilledButton.tonal", | ||
); | ||
} else { | ||
builder.addSimpleReplacement( | ||
node.constructorName.sourceRange, | ||
node.constructorName.type.name2.lexeme, | ||
); | ||
} | ||
|
||
for (var argument in node.argumentList.arguments) { | ||
if (argument is NamedExpression) { | ||
if (argument.name.label.name == "label") { | ||
builder.addSimpleReplacement( | ||
argument.name.sourceRange, | ||
"child:", | ||
); | ||
} | ||
|
||
if (argument.name.label.name == "icon") { | ||
builder.addDeletion( | ||
SourceRange( | ||
argument.sourceRange.offset, | ||
argument.sourceRange.length + | ||
(argument.endToken.next?.lexeme == "," ? 1 : 0), | ||
), | ||
); | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
} | ||
} |
117 changes: 117 additions & 0 deletions
117
packages/masamune_lints/lib/buttons/masamune_button_type.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
part of '/masamune_lints.dart'; | ||
|
||
const _kConvertToOtherButtonPriority = 27; | ||
const _kAddOrRemoveIconPriority = 27; | ||
|
||
enum _MaterialButtonType { | ||
elevated( | ||
buttonName: "ElevatedButton", | ||
className: "ElevatedButton", | ||
priority: _kConvertToOtherButtonPriority, | ||
typeChecker: TypeChecker.fromName( | ||
"ElevatedButton", | ||
packageName: "flutter", | ||
), | ||
), | ||
filled( | ||
buttonName: "FilledButton", | ||
className: "FilledButton", | ||
priority: _kConvertToOtherButtonPriority, | ||
typeChecker: TypeChecker.fromName( | ||
"FilledButton", | ||
packageName: "flutter", | ||
), | ||
), | ||
filledTonal( | ||
buttonName: "FilledTonalButton", | ||
className: "FilledButton", | ||
priority: _kConvertToOtherButtonPriority, | ||
typeChecker: TypeChecker.fromName( | ||
"FilledButton", | ||
packageName: "flutter", | ||
), | ||
), | ||
outlined( | ||
buttonName: "OutlinedButton", | ||
className: "OutlinedButton", | ||
priority: _kConvertToOtherButtonPriority, | ||
typeChecker: TypeChecker.fromName( | ||
"OutlinedButton", | ||
packageName: "flutter", | ||
), | ||
), | ||
text( | ||
buttonName: "TextButton", | ||
className: "TextButton", | ||
priority: _kConvertToOtherButtonPriority, | ||
typeChecker: TypeChecker.fromName( | ||
"TextButton", | ||
packageName: "flutter", | ||
), | ||
); | ||
|
||
const _MaterialButtonType({ | ||
required this.buttonName, | ||
required this.className, | ||
required this.priority, | ||
required this.typeChecker, | ||
}); | ||
final String buttonName; | ||
final String className; | ||
final int priority; | ||
final TypeChecker typeChecker; | ||
|
||
TypeChecker getBaseType() { | ||
return TypeChecker.any( | ||
_MaterialButtonType.values | ||
.where((e) => e != this) | ||
.map((e) => e.typeChecker), | ||
); | ||
} | ||
} | ||
|
||
enum _SupportedIdentifier { | ||
icon, | ||
tonal, | ||
tonalIcon; | ||
|
||
bool get isTonal { | ||
switch (this) { | ||
case _SupportedIdentifier.icon: | ||
return false; | ||
case _SupportedIdentifier.tonal: | ||
return true; | ||
case _SupportedIdentifier.tonalIcon: | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
|
||
bool get hasIcon { | ||
switch (this) { | ||
case _SupportedIdentifier.icon: | ||
return true; | ||
case _SupportedIdentifier.tonal: | ||
return false; | ||
case _SupportedIdentifier.tonalIcon: | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
} | ||
|
||
extension _SimpleIdentifierExtensions on SimpleIdentifier { | ||
_SupportedIdentifier? toSupportedIdentifier() { | ||
switch (name) { | ||
case "icon": | ||
return _SupportedIdentifier.icon; | ||
case "tonal": | ||
return _SupportedIdentifier.tonal; | ||
case "tonalIcon": | ||
return _SupportedIdentifier.tonalIcon; | ||
} | ||
return null; | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
packages/masamune_lints/lib/common/masamune_limit_if_nesting.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
part of '/masamune_lints.dart'; | ||
|
||
const _kMaxNestingCount = 3; | ||
|
||
class _MasamuneLimitIfNesting extends DartLintRule { | ||
const _MasamuneLimitIfNesting() | ||
: super( | ||
code: _code, | ||
); | ||
|
||
static const _code = LintCode( | ||
name: "masamune_if_nesting_should_limit", | ||
problemMessage: | ||
"Nesting hierarchy for if should be limited to $_kMaxNestingCount units. ifのネスト階層は$_kMaxNestingCount個までにしてください。", | ||
errorSeverity: ErrorSeverity.WARNING, | ||
); | ||
|
||
@override | ||
void run( | ||
CustomLintResolver resolver, | ||
ErrorReporter reporter, | ||
CustomLintContext context, | ||
) { | ||
context.registry.addIfStatement((node) { | ||
int nestingLevel = 0; | ||
AstNode? currentNode = node; | ||
|
||
while (currentNode != null) { | ||
if (currentNode is IfStatement && currentNode.elseStatement == null) { | ||
nestingLevel++; | ||
} | ||
currentNode = currentNode.parent; | ||
} | ||
|
||
if (nestingLevel > _kMaxNestingCount) { | ||
reporter.reportErrorForNode(_code, node); | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.