Skip to content

Commit

Permalink
feat: improve error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
tilucasoli committed Sep 27, 2024
1 parent 1ce9080 commit 1d86e23
Show file tree
Hide file tree
Showing 14 changed files with 176 additions and 82 deletions.
10 changes: 9 additions & 1 deletion packages/mix/lib/src/attributes/border/border_dto.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// ignore_for_file: prefer_relative_imports,avoid-importing-entrypoint-exports
import 'package:flutter/foundation.dart';

Check notice on line 2 in packages/mix/lib/src/attributes/border/border_dto.dart

View workflow job for this annotation

GitHub Actions / Test

The import of 'package:flutter/foundation.dart' is unnecessary because all of the used elements are also provided by the import of 'package:flutter/material.dart'.

Try removing the import directive. See https://dart.dev/diagnostics/unnecessary_import to learn more about this problem.

Check notice on line 2 in packages/mix/lib/src/attributes/border/border_dto.dart

View workflow job for this annotation

GitHub Actions / Test Min SDK

The import of 'package:flutter/foundation.dart' is unnecessary because all of the used elements are also provided by the import of 'package:flutter/material.dart'.

Try removing the import directive. See https://dart.dev/diagnostics/unnecessary_import to learn more about this problem.
import 'package:flutter/material.dart';
import 'package:mix/mix.dart';
import 'package:mix_annotations/mix_annotations.dart';

import '../../core/factory/mix_provider.dart';

Check warning on line 7 in packages/mix/lib/src/attributes/border/border_dto.dart

View workflow job for this annotation

GitHub Actions / Test

Unused import: '../../core/factory/mix_provider.dart'.

Try removing the import directive. See https://dart.dev/diagnostics/unused_import to learn more about this problem.

Check warning on line 7 in packages/mix/lib/src/attributes/border/border_dto.dart

View workflow job for this annotation

GitHub Actions / Test Min SDK

Unused import: '../../core/factory/mix_provider.dart'.

Try removing the import directive. See https://dart.dev/diagnostics/unused_import to learn more about this problem.
import '../../internal/mix_error.dart';

part 'border_dto.g.dart';

@immutable
Expand Down Expand Up @@ -151,6 +155,10 @@ extension BoxBorderExt on BoxBorder {
final self = this;
if (self is Border) return (self).toDto();
if (self is BorderDirectional) return (self).toDto();
throw UnimplementedError();

throw MixError.unsupportedTypeInDto(
BoxBorder,
['Border', 'BorderDirectional'],
);
}
}
18 changes: 8 additions & 10 deletions packages/mix/lib/src/attributes/border/border_radius_dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:mix/mix.dart';
import 'package:mix_annotations/mix_annotations.dart';

import '../../internal/diagnostic_properties_builder_ext.dart';
import '../../internal/mix_error.dart';

part 'border_radius_dto.g.dart';

Expand Down Expand Up @@ -147,16 +148,13 @@ final class BorderRadiusDirectionalDto

extension BorderRadiusGeometryMixExt on BorderRadiusGeometry {
BorderRadiusGeometryDto toDto() {
if (this is BorderRadius) {
return (this as BorderRadius).toDto();
}
if (this is BorderRadiusDirectional) {
return (this as BorderRadiusDirectional).toDto();
}
throw ArgumentError.value(
this,
'radius',
'BorderRadiusGeometry type is not supported',
final self = this;
if (self is BorderRadius) return self.toDto();
if (self is BorderRadiusDirectional) return self.toDto();

throw MixError.unsupportedTypeInDto(
BorderRadiusGeometry,
['BorderRadius', 'BorderRadiusDirectional'],
);
}
}
21 changes: 13 additions & 8 deletions packages/mix/lib/src/attributes/border/shape_border_dto.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// ignore_for_file: prefer_relative_imports, avoid-importing-entrypoint-exports
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:mix/mix.dart';
import 'package:mix_annotations/mix_annotations.dart';
Expand Down Expand Up @@ -302,14 +303,18 @@ extension ShapeBorderExt on ShapeBorder {
if (self is StarBorder) return (self).toDto();
if (self is MixOutlinedBorder) return (self).toDto();

throw ArgumentError.value(
this,
'shapeBorder',
'Unsupported ShapeBorder type.\n'
'If you are trying to create a custom ShapeBorder, it must extend MixOutlinedBorder.'
' Otherwise, use a built-in Mix shape.\n'
'Custom ShapeBorders that do not extend MixOutlinedBorder will not work with Mix.',
);
throw FlutterError.fromParts([
ErrorSummary('Unsupported ShapeBorder type.'),
ErrorDescription(
'If you are trying to create a custom ShapeBorder, it must extend MixOutlinedBorder. '
'Otherwise, use a built-in Mix shape such as BeveledRectangleBorder, CircleBorder, '
'ContinuousRectangleBorder, LinearBorder, RoundedRectangleBorder, StadiumBorder, or StarBorder.',
),
ErrorHint(
'Custom ShapeBorders that do not extend MixOutlinedBorder will not work with Mix.',
),
DiagnosticsProperty<ShapeBorder>('The unsupported ShapeBorder was', this),
]);
}
}

Expand Down
15 changes: 9 additions & 6 deletions packages/mix/lib/src/attributes/decoration/decoration_dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:mix/mix.dart';
import 'package:mix_annotations/mix_annotations.dart';

import '../../internal/diagnostic_properties_builder_ext.dart';
import '../../internal/mix_error.dart';

part 'decoration_dto.g.dart';

Expand Down Expand Up @@ -265,12 +266,14 @@ ShapeDecorationDto _toShapeDecorationDto(BoxDecorationDto dto) {

extension DecorationMixExt on Decoration {
DecorationDto toDto() {
if (this is BoxDecoration) {
return (this as BoxDecoration).toDto();
} else if (this is ShapeDecoration) {
return (this as ShapeDecoration).toDto();
}
throw Exception('Unknown decoration type: $runtimeType');
final self = this;
if (self is BoxDecoration) return self.toDto();
if (self is ShapeDecoration) return self.toDto();

throw MixError.unsupportedTypeInDto(
Decoration,
['BoxDecoration', 'ShapeDecoration'],
);
}
}

Expand Down
35 changes: 25 additions & 10 deletions packages/mix/lib/src/attributes/gradient/gradient_dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import 'package:flutter/widgets.dart';
import 'package:mix/mix.dart';
import 'package:mix_annotations/mix_annotations.dart';

import '../../internal/mix_error.dart';

part 'gradient_dto.g.dart';

/// Represents a base Data transfer object of [Gradient]
Expand Down Expand Up @@ -153,7 +155,10 @@ extension GradientExt on Gradient {
if (self is RadialGradient) return (self).toDto();
if (self is SweepGradient) return (self).toDto();

throw UnimplementedError();
throw MixError.unsupportedTypeInDto(
Gradient,
['LinearGradient', 'RadialGradient', 'SweepGradient'],
);
}
}

Expand All @@ -176,15 +181,25 @@ final class GradientUtility<T extends Attribute>
///
/// Throws an [UnimplementedError] if the given gradient type is not supported.
T as(Gradient gradient) {
if (gradient is RadialGradient) {
return radial.as(gradient);
} else if (gradient is LinearGradient) {
return linear.as(gradient);
} else if (gradient is SweepGradient) {
return sweep.as(gradient);
switch (gradient) {
case RadialGradient():
return radial.as(gradient);
case LinearGradient():
return linear.as(gradient);
case SweepGradient():
return sweep.as(gradient);
}
throw UnimplementedError(
'Cannot create $T from gradient of type ${gradient.runtimeType}',
);

throw FlutterError.fromParts([
ErrorSummary('Mix does not support custom gradient implementations.'),
ErrorDescription(
'The provided gradient of type ${gradient.runtimeType} is not supported.',
),
ErrorHint(
'If you believe this gradient type should be supported, please open an issue at '
'https://github.com/conceptadev/mix/issues/new/choose with details about your implementation '
'and its use case.',
),
]);
}
}
15 changes: 14 additions & 1 deletion packages/mix/lib/src/attributes/shadow/shadow_util.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';

Check notice on line 1 in packages/mix/lib/src/attributes/shadow/shadow_util.dart

View workflow job for this annotation

GitHub Actions / Test

The import of 'package:flutter/foundation.dart' is unnecessary because all of the used elements are also provided by the import of 'package:flutter/material.dart'.

Try removing the import directive. See https://dart.dev/diagnostics/unnecessary_import to learn more about this problem.

Check notice on line 1 in packages/mix/lib/src/attributes/shadow/shadow_util.dart

View workflow job for this annotation

GitHub Actions / Test Min SDK

The import of 'package:flutter/foundation.dart' is unnecessary because all of the used elements are also provided by the import of 'package:flutter/material.dart'.

Try removing the import directive. See https://dart.dev/diagnostics/unnecessary_import to learn more about this problem.
import 'package:flutter/material.dart';

import '../../core/attribute.dart';
Expand Down Expand Up @@ -87,7 +88,19 @@ final class ElevationUtility<T extends Attribute>
///
/// Throws an [AssertionError] if the provided [value] is not a valid elevation value.
T call(int value) {
assert(kElevationToShadow.containsKey(value), 'Invalid elevation value');
if (!kElevationToShadow.containsKey(value)) {
throw FlutterError.fromParts(
[
ErrorSummary('Invalid elevation value provided.'),
ErrorDescription(
'The elevation value $value is not a valid predefined elevation.',
),
ErrorHint(
'Please use one of the predefined elevation values: ${kElevationToShadow.keys.join(", ")}.',
),
],
);
}

final boxShadows = kElevationToShadow[value]!.map((e) => e.toDto());

Expand Down
16 changes: 7 additions & 9 deletions packages/mix/lib/src/attributes/spacing/edge_insets_dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:mix/mix.dart';
import 'package:mix_annotations/mix_annotations.dart';

import '../../internal/diagnostic_properties_builder_ext.dart';
import '../../internal/mix_error.dart';

part 'edge_insets_dto.g.dart';

Expand Down Expand Up @@ -156,16 +157,13 @@ final class EdgeInsetsDirectionalDto

extension EdgeInsetsGeometryExt on EdgeInsetsGeometry {
SpacingDto toDto() {
if (this is EdgeInsetsDirectional) {
return (this as EdgeInsetsDirectional).toDto();
} else if (this is EdgeInsets) {
return (this as EdgeInsets).toDto();
}
final self = this;
if (self is EdgeInsetsDirectional) return self.toDto();
if (self is EdgeInsets) return self.toDto();

throw ArgumentError.value(
this,
'edgeInsets',
'Must be either EdgeInsets or EdgeInsetsDirectional',
throw MixError.unsupportedTypeInDto(
EdgeInsetsGeometry,
['EdgeInsetsDirectional', 'EdgeInsets'],
);
}
}
15 changes: 12 additions & 3 deletions packages/mix/lib/src/attributes/text_style/text_style_dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,18 @@ final class TextStyleDataRef extends TextStyleData {
@override
TextStyleDataRef merge(covariant TextStyleDataRef? other) {
if (other == null) return this;
throw UnsupportedError(
'Cannot merge $this with $other, most likely there is an error on Mix',
);
throw FlutterError.fromParts([
ErrorSummary('Cannot merge TextStyleDataRef instances'),
ErrorDescription(
'An attempt was made to merge incompatible TextStyleDataRef objects. '
'Attempted to merge: $this with $other',
),
ErrorHint('This is likely due to an internal error in the Mix library.'),
ErrorHint(
'Please open an issue on GitHub: https://github.com/yourorganization/mix/issues, '
'Explain how you encountered this error, and provide the code that triggered it.',
),
]);
}

@override
Expand Down
43 changes: 28 additions & 15 deletions packages/mix/lib/src/core/factory/style_mix.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,34 @@ class Style with EqualityMixin {
final styleList = <StyledAttribute>[];

for (final attribute in attributes) {
if (attribute is StyledAttribute) {
styleList.add(attribute);
} else if (attribute is VariantAttribute) {
applyVariants.add(attribute);
} else if (attribute is NestedStyleAttribute) {
applyVariants.addAll(attribute.value.variants.values);
styleList.addAll(attribute.value.styles.values);
} else if (attribute is SpecUtility) {
if (attribute.attributeValue != null) {
final nestedStyle = Style.create([attribute.attributeValue!]);
styleList.addAll(nestedStyle.styles.values);
applyVariants.addAll(nestedStyle.variants.values);
}
} else {
throw UnsupportedError('Unsupported attribute type: $attribute');
switch (attribute) {
case StyledAttribute():
styleList.add(attribute);
case VariantAttribute():
applyVariants.add(attribute);
case NestedStyleAttribute():
applyVariants.addAll(attribute.value.variants.values);
styleList.addAll(attribute.value.styles.values);
case SpecUtility():
if (attribute.attributeValue != null) {
final nestedStyle = Style.create([attribute.attributeValue!]);
styleList.addAll(nestedStyle.styles.values);
applyVariants.addAll(nestedStyle.variants.values);
}
default:
throw FlutterError.fromParts([
ErrorSummary(
'Unsupported attribute type encountered in Style creation.',
),
ErrorDescription(
'The attribute of type ${attribute.runtimeType} is not supported.',
),
ErrorHint(
'Custom Attributes must be subclasses of one of the following types: '
'StyledAttribute, VariantAttribute, NestedStyleAttribute, or SpecUtility. '
'Please ensure your attribute implements one of these supported types.',
),
]);
}
}

Expand Down
33 changes: 33 additions & 0 deletions packages/mix/lib/src/internal/mix_error.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:flutter/foundation.dart';

abstract class MixError {
static FlutterError unsupportedTypeInDto(
Type type,
List<String> supportedTypes,
) {
final supportedTypesFormated =
'${supportedTypes.sublist(0, supportedTypes.length - 1).join(', ')} and ${supportedTypes.last}';

return FlutterError.fromParts([
ErrorSummary('Unsupported $type type'),
ErrorDescription(
'The toDto() method is not implemented for this $type subclass.',
),
ErrorHint('Only $supportedTypesFormated are currently supported.'),
]);
}

static FlutterError accessTokenValue(String token, String field) {
return FlutterError.fromParts([
ErrorSummary('Invalid access: $token cannot access field $field'),
ErrorDescription(
'The $field field cannot be directly accessed through TextStyleRef. '
'Ensure you are using the appropriate methods or properties provided by TextStyleToken to interact with the style properties.',
),
ErrorHint(
'Consider using TextStyleToken.resolve() to access the $field. '
'This method ensures that $token is used within the appropriate context where $field is available.',
),
]);
}
}
17 changes: 3 additions & 14 deletions packages/mix/lib/src/theme/tokens/text_style_token.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/widgets.dart';

import '../../internal/mix_error.dart';
import '../mix/mix_theme.dart';
import 'mix_token.dart';

Expand Down Expand Up @@ -163,18 +164,6 @@ final class TextStyleRef extends TextStyle with TokenRef<TextStyleToken> {
int get hashCode => token.name.hashCode;
}

TokenFieldAccessError _e(String token, String field) {
return TokenFieldAccessError(token, field);
}

class TokenFieldAccessError extends Error {
final String tokenName;
final String fieldName;

TokenFieldAccessError(this.tokenName, this.fieldName);

@override
String toString() {
return '$tokenName cannot have field $fieldName because it is outside of context';
}
FlutterError _e(String token, String field) {
return MixError.accessTokenValue(token, field);
}
14 changes: 12 additions & 2 deletions packages/mix/lib/src/variants/context_variant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,18 @@ final class ContextVariantBuilder extends VariantAttribute<ContextVariant> {

@override
@protected
Style get value => throw UnimplementedError(
'This is a ContextVariantBuilder you need to call build(context)',
Style get value => throw FlutterError.fromParts(
[
ErrorSummary(
'Attempted to access value of ContextVariantBuilder directly.',
),
ErrorDescription(
'This is a ContextVariantBuilder and requires a BuildContext to resolve.',
),
ErrorHint(
'Use the build(context) method instead of accessing value directly.',
),
],
);

@override
Expand Down
Loading

0 comments on commit 1d86e23

Please sign in to comment.