Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@
- Implement `xsd:gMonthDay` codec and data type
- Implement `xsd:duration` codec and data type
- Implement `xsd:datetime` codec and data type
- Implement `xsd:anyUri` codec
- Implement `xsd:anyUri` codec
- Implement `xsd:decimal` codec
Comment thread
mark-dropbear marked this conversation as resolved.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ This library aims to support the following XSD 1.1 built-in datatypes that are c
| `xsd:Name` | ✅ | ✅ | `String` | `dart:core` |
| `xsd:language` | ✅ | ✅ | `Locale` | `package:intl` |
| `xsd:NCName` | ✅ | ✅ | `String` | `dart:core` |
| `xsd:decimal` | ✅ | ❌ | `Decimal` | `package:decimal` |
| `xsd:decimal` | ✅ | ✅ | `Decimal` | `package:decimal` |
| `xsd:double` | ✅ | ❌ | `double` | `dart:core` |
| `xsd:float` | ✅ | ❌ | `double` | `dart:core` |
| `xsd:integer` | ✅ | ❌ | `BigInt` | `dart:core` |
Expand Down
1 change: 1 addition & 0 deletions lib/src/codecs/codecs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ export 'g_month_day/gregorian_month_day_codec.dart';
export 'duration/xsd_duration_codec.dart';
export 'datetime/xsd_datetime_codec.dart';
export 'any_uri/any_uri_codec.dart';
export 'decimal/decimal_codec.dart';
41 changes: 41 additions & 0 deletions lib/src/codecs/decimal/decimal_codec.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import 'dart:convert';

import 'package:decimal/decimal.dart';
import 'package:xsd/src/helpers/whitespace.dart';

/// A [Codec] that converts between XSD `decimal` strings and [Decimal] objects.
class XsdDecimalCodec extends Codec<Decimal, String> {
const XsdDecimalCodec();

@override
Converter<Decimal, String> get encoder => const XsdDecimalEncoder();

@override
Converter<String, Decimal> get decoder => const XsdDecimalDecoder();
}

class XsdDecimalEncoder extends Converter<Decimal, String> {
const XsdDecimalEncoder();

@override
String convert(Decimal input) => input.toString();
}

class XsdDecimalDecoder extends Converter<String, Decimal> {
const XsdDecimalDecoder();

static final _validationRegex = RegExp(
r'^(\+|-)?([0-9]+(\.[0-9]*)?|\.[0-9]+)$',
);

@override
Decimal convert(String input) {
final trimmed = processWhiteSpace(input, Whitespace.collapse);

if (!_validationRegex.hasMatch(trimmed)) {
throw FormatException('Invalid XSD decimal format', input);
}

return Decimal.parse(trimmed);
}
}
34 changes: 34 additions & 0 deletions test/codecs/decimal_codec_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import 'package:decimal/decimal.dart';
import 'package:test/test.dart';
import 'package:xsd/xsd.dart';

void main() {
group('XsdDecimalCodec', () {
const codec = XsdDecimalCodec();

test('should encode valid decimal', () {
expect(codec.encode(Decimal.parse('123.45')), '123.45');
expect(codec.encode(Decimal.parse('-123.45')), '-123.45');
});

test('should decode valid decimal', () {
expect(codec.decode('123.45'), Decimal.parse('123.45'));
expect(codec.decode('-123.45'), Decimal.parse('-123.45'));
expect(codec.decode(' +123.45 '), Decimal.parse('123.45'));
expect(codec.decode('.45'), Decimal.parse('0.45'));
Comment thread
mark-dropbear marked this conversation as resolved.
expect(codec.decode('123'), Decimal.parse('123'));
expect(codec.decode('+123'), Decimal.parse('123'));
expect(codec.decode('-123'), Decimal.parse('-123'));
expect(codec.decode('123.'), Decimal.parse('123'));
});

test('should throw on invalid decimal', () {
expect(() => codec.decode('12.3.4'), throwsFormatException);
expect(() => codec.decode('abc'), throwsFormatException);
expect(
() => codec.decode('1E4'),
throwsFormatException,
); // Scientific notation not allowed in decimal
});
});
}