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
10 changes: 5 additions & 5 deletions lib/src/extensions/decode.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ extension _$Decode on QS {
? val.split(',')
: val;

static Map _parseQueryStringValues(
static Map<String, dynamic> _parseQueryStringValues(
String str, [
DecodeOptions options = const DecodeOptions(),
]) {
final Map obj = {};
final Map<String, dynamic> obj = {};

final String cleanStr =
options.ignoreQueryPrefix ? str.replaceFirst('?', '') : str;
Expand Down Expand Up @@ -107,7 +107,7 @@ extension _$Decode on QS {
? List<dynamic>.empty(growable: true)
: [if (leaf is Iterable) ...leaf else leaf];
} else {
obj = Map.of({});
obj = <String, dynamic>{};
final String cleanRoot = root.startsWith('[') && root.endsWith(']')
? root.slice(1, root.length - 1)
: root;
Expand All @@ -116,7 +116,7 @@ extension _$Decode on QS {
: cleanRoot;
final int? index = int.tryParse(decodedRoot);
if (!options.parseLists && decodedRoot == '') {
obj = Map.of({0: leaf});
obj = <String, dynamic>{'0': leaf};
} else if (index != null &&
index >= 0 &&
root != decodedRoot &&
Expand All @@ -130,7 +130,7 @@ extension _$Decode on QS {
);
obj[index] = leaf;
} else {
obj[index ?? decodedRoot] = leaf;
obj[index?.toString() ?? decodedRoot] = leaf;
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/methods.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:qs_dart/src/models/encode_options.dart';
import 'package:qs_dart/src/qs.dart';

/// Convenience method for [QS.decode]
Map decode(
Map<String, dynamic> decode(
dynamic input, [
DecodeOptions options = const DecodeOptions(),
]) =>
Expand Down
42 changes: 22 additions & 20 deletions lib/src/qs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,43 +19,45 @@ part 'extensions/encode.dart';

/// A query string decoder (parser) and encoder (stringifier) class.
final class QS {
/// Decodes a [String] or [Map] into a [Map].
/// Decodes a [String] or [Map<String, dynamic>] into a [Map<String, dynamic>].
/// Providing custom [options] will override the default behavior.
static Map decode(
static Map<String, dynamic> decode(
dynamic input, [
DecodeOptions options = const DecodeOptions(),
]) {
if (!(input is String? || input is Map?)) {
if (!(input is String? || input is Map<String, dynamic>?)) {
throw ArgumentError.value(
input,
'input',
'The input must be a String or a Map',
'The input must be a String or a Map<String, dynamic>',
);
}

if (input?.isEmpty ?? true) {
return Map.of({});
return <String, dynamic>{};
}

Map? tempObj = input is String
Map<String, dynamic>? tempObj = input is String
? _$Decode._parseQueryStringValues(input, options)
: input;
Map obj = {};
Map<String, dynamic> obj = {};

// Iterate over the keys and setup the new object
for (final MapEntry entry in tempObj?.entries ?? List.empty()) {
final newObj = _$Decode._parseKeys(
entry.key,
entry.value,
options,
input is String,
);

obj = Utils.merge(
obj,
newObj,
options,
);
if (tempObj?.isNotEmpty ?? false) {
for (final MapEntry<String, dynamic> entry in tempObj!.entries) {
final newObj = _$Decode._parseKeys(
entry.key,
entry.value,
options,
input is String,
);

obj = Utils.merge(

Check warning

Code scanning / Dartanalyzer (reported by Codacy)

Undefined name 'Utils'.

Undefined name 'Utils'.
obj,
newObj,
options,
);
}
}

return Utils.compact(obj);
Expand Down
33 changes: 20 additions & 13 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,12 @@ final class Utils {
}
} else if (target is Map) {
if (source is Iterable) {
target = Map.of(target)
..addAll({
for (final (int i, dynamic item) in source.indexed)
if (item is! Undefined) i: item
});
target = <String, dynamic>{
for (final MapEntry entry in target.entries)
entry.key.toString(): entry.value,
for (final (int i, dynamic item) in source.indexed)
if (item is! Undefined) i.toString(): item

Check warning

Code scanning / Dartanalyzer (reported by Codacy)

The name 'Undefined' isn't defined, so it can't be used in an 'is' expression.

The name 'Undefined' isn't defined, so it can't be used in an 'is' expression.
};
}
} else if (source != null) {
if (target is! Iterable && source is Iterable) {
Expand All @@ -105,9 +106,9 @@ final class Utils {

if (target == null || target is! Map) {
if (target is Iterable) {
return Map.of({
return Map<String, dynamic>.of({
for (final (int i, dynamic item) in target.indexed)
if (item is! Undefined) i: item,
if (item is! Undefined) i.toString(): item,

Check warning

Code scanning / Dartanalyzer (reported by Codacy)

The name 'Undefined' isn't defined, so it can't be used in an 'is' expression.

The name 'Undefined' isn't defined, so it can't be used in an 'is' expression.
...source,
});
}
Expand All @@ -124,13 +125,19 @@ final class Utils {
];
}

Map mergeTarget = target is Iterable && source is! Iterable
? (target as Iterable).toList().whereNotUndefined().asMap()
: Map.of(target);
Map<String, dynamic> mergeTarget = target is Iterable && source is! Iterable
? {
for (final (int i, dynamic item) in (target as Iterable).indexed)
if (item is! Undefined) i.toString(): item

Check warning

Code scanning / Dartanalyzer (reported by Codacy)

The name 'Undefined' isn't defined, so it can't be used in an 'is' expression.

The name 'Undefined' isn't defined, so it can't be used in an 'is' expression.
}
: {
for (final MapEntry entry in target.entries)
entry.key.toString(): entry.value
};

return source.entries.fold(mergeTarget, (Map acc, MapEntry entry) {
acc.update(
entry.key,
entry.key.toString(),
(value) => merge(
value,
entry.value,
Expand Down Expand Up @@ -332,8 +339,8 @@ final class Utils {
}
}

static Map compact(Map value) {
final List<Map> queue = [
static Map<String, dynamic> compact(Map<String, dynamic> value) {
final List<Map<String, dynamic>> queue = [
{
'obj': {'o': value},
'prop': 'o',
Expand Down
10 changes: 5 additions & 5 deletions test/fixtures/data/empty_test_cases.dart
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,8 @@ const List<Map<String, dynamic>> emptyTestCases = [
'repeat': '=a&=b& =1'
},
'noEmptyKeys': {
0: 'a',
1: 'b',
'0': 'a',
'1': 'b',
' ': ['1']
}
},
Expand All @@ -256,8 +256,8 @@ const List<Map<String, dynamic>> emptyTestCases = [
'a': ['1', '2']
},
'noEmptyKeys': {
0: 'a',
1: 'b',
'0': 'a',
'1': 'b',
'a': ['1', '2']
},
'stringifyOutput': {
Expand Down Expand Up @@ -292,6 +292,6 @@ const List<Map<String, dynamic>> emptyTestCases = [
'indices': '[0]=a&[1]=b',
'repeat': '=a&=b'
},
'noEmptyKeys': {0: 'a', 1: 'b'}
'noEmptyKeys': {'0': 'a', '1': 'b'}
}
];
16 changes: 10 additions & 6 deletions test/unit/array_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@ import 'package:test/test.dart';
void main() {
group('SplayTreeMap', () {
test('indices are ordered in value', () {
final SplayTreeMap<int, String> array =
SplayTreeMap<int, String>.from({1: 'a', 0: 'b', 2: 'c'});
final SplayTreeMap<String, String> array =
SplayTreeMap<String, String>.from({
'1': 'a',
'0': 'b',
'2': 'c',
});

expect(array.values, ['b', 'a', 'c']);
});

test('indices are ordered in value 2', () {
final SplayTreeMap<int, String> array = SplayTreeMap<int, String>();
array[1] = 'c';
array[0] = 'b';
array[2] = 'd';
final SplayTreeMap<String, String> array = SplayTreeMap<String, String>();
array['1'] = 'c';
array['0'] = 'b';
array['2'] = 'd';

expect(array.values, ['b', 'c', 'd']);
});
Expand Down
Loading