yaml_edit nullsafety (#107)
* Null safey implimentation
* Adding test for nested parseAt with null value
* Change `parseAt()` signature only YamlNode
* Removing unnecessary ArgumentError.checkNotNull()
* Updating remove() signature and doc
* Change parseAt() orElse documentation
Co-authored-by: Jonas Finnemann Jensen <jopsen@gmail.com>
diff --git a/lib/src/editor.dart b/lib/src/editor.dart
index 8f06d8f..c6f86de 100644
--- a/lib/src/editor.dart
+++ b/lib/src/editor.dart
@@ -120,15 +120,12 @@
factory YamlEditor(String yaml) => YamlEditor._(yaml);
- YamlEditor._(this._yaml) {
- ArgumentError.checkNotNull(_yaml);
+ YamlEditor._(this._yaml) : _contents = loadYamlNode(_yaml) {
_initialize();
}
- /// Loads [_contents] from [_yaml], and traverses the YAML tree formed to
- /// detect alias nodes.
+ /// Traverses the YAML tree formed to detect alias nodes.
void _initialize() {
- _contents = loadYamlNode(_yaml);
_aliases = {};
/// Performs a DFS on [_contents] to detect alias nodes.
@@ -158,14 +155,17 @@
///
/// If [orElse] is omitted, it defaults to throwing a [ArgumentError].
///
- /// To get `null` when [path] does not point to a value in the [YamlNode]-tree,
- /// simply pass `orElse: () => null`.
+ /// To get a default value when [path] does not point to a value in the
+ /// [YamlNode]-tree, simply pass `orElse: () => ...`.
///
/// **Example:** (using orElse)
/// ```dart
/// final myYamlEditor('{"key": "value"}');
- /// final value = myYamlEditor.valueAt(['invalid', 'path'], orElse: () => null);
- /// print(value) // null
+ /// final node = myYamlEditor.valueAt(
+ /// ['invalid', 'path'],
+ /// orElse: () => wrapAsYamlNode(null),
+ /// );
+ /// print(node.value); // null
/// ```
///
/// **Example:** (common usage)
@@ -197,9 +197,7 @@
/// print(newNode.value); // "YAML"
/// print(node.value); // "YAML Ain't Markup Language"
/// ```
- YamlNode parseAt(Iterable<Object> path, {YamlNode Function() orElse}) {
- ArgumentError.checkNotNull(path, 'path');
-
+ YamlNode parseAt(Iterable<Object?> path, {YamlNode Function()? orElse}) {
return _traverse(path, orElse: orElse);
}
@@ -244,9 +242,7 @@
/// - test
/// - 2
/// ```
- void update(Iterable<Object> path, Object value) {
- ArgumentError.checkNotNull(path, 'path');
-
+ void update(Iterable<Object?> path, Object? value) {
final valueNode = wrapAsYamlNode(value);
if (path.isEmpty) {
@@ -265,6 +261,9 @@
final parentNode = _traverse(collectionPath, checkAlias: true);
if (parentNode is YamlList) {
+ if (keyOrIndex is! int) {
+ throw PathError(path, path, parentNode);
+ }
final expected = wrapAsYamlNode(
[...parentNode.nodes]..[keyOrIndex] = valueNode,
);
@@ -294,8 +293,7 @@
/// final doc = YamlEditor('[0, 1]');
/// doc.appendToList([], 2); // [0, 1, 2]
/// ```
- void appendToList(Iterable<Object> path, Object value) {
- ArgumentError.checkNotNull(path, 'path');
+ void appendToList(Iterable<Object?> path, Object? value) {
final yamlList = _traverseToList(path);
insertIntoList(path, yamlList.length, value);
@@ -311,9 +309,7 @@
/// final doc = YamlEditor('[1, 2]');
/// doc.prependToList([], 0); // [0, 1, 2]
/// ```
- void prependToList(Iterable<Object> path, Object value) {
- ArgumentError.checkNotNull(path, 'path');
-
+ void prependToList(Iterable<Object?> path, Object? value) {
insertIntoList(path, 0, value);
}
@@ -329,8 +325,7 @@
/// final doc = YamlEditor('[0, 2]');
/// doc.insertIntoList([], 1, 1); // [0, 1, 2]
/// ```
- void insertIntoList(Iterable<Object> path, int index, Object value) {
- ArgumentError.checkNotNull(path, 'path');
+ void insertIntoList(Iterable<Object?> path, int index, Object? value) {
final valueNode = wrapAsYamlNode(value);
final list = _traverseToList(path, checkAlias: true);
@@ -360,13 +355,8 @@
/// doc.spliceList([], 1, 0, ['Feb']); // [Jan, Feb, March, April, June]
/// doc.spliceList([], 4, 1, ['May']); // [Jan, Feb, March, April, May]
/// ```
- Iterable<YamlNode> spliceList(Iterable<Object> path, int index,
- int deleteCount, Iterable<Object> values) {
- ArgumentError.checkNotNull(path, 'path');
- ArgumentError.checkNotNull(index, 'index');
- ArgumentError.checkNotNull(deleteCount, 'deleteCount');
- ArgumentError.checkNotNull(values, 'values');
-
+ Iterable<YamlNode> spliceList(Iterable<Object?> path, int index,
+ int deleteCount, Iterable<Object?> values) {
final list = _traverseToList(path, checkAlias: true);
RangeError.checkValueInInterval(index, 0, list.length);
@@ -417,17 +407,15 @@
/// - 2 # comment 2
/// '''
/// ```
- YamlNode remove(Iterable<Object> path) {
- ArgumentError.checkNotNull(path, 'path');
-
- SourceEdit edit;
- YamlNode expectedNode;
+ YamlNode remove(Iterable<Object?> path) {
+ SourceEdit? edit;
+ var expectedNode = wrapAsYamlNode(null);
final nodeToRemove = _traverse(path, checkAlias: true);
if (path.isEmpty) {
edit = SourceEdit(0, _yaml.length, '');
- /// Parsing an empty YAML document returns `null`.
+ /// Parsing an empty YAML document returns YamlScalar with value `null`.
_performEdit(edit, path, expectedNode);
return nodeToRemove;
}
@@ -438,7 +426,7 @@
final parentNode = _traverse(collectionPath);
if (parentNode is YamlList) {
- edit = removeInList(this, parentNode, keyOrIndex);
+ edit = removeInList(this, parentNode, keyOrIndex as int);
expectedNode = wrapAsYamlNode(
[...parentNode.nodes]..removeAt(keyOrIndex),
);
@@ -449,7 +437,7 @@
updatedYamlMap(parentNode, (nodes) => nodes.remove(keyOrIndex));
}
- _performEdit(edit, collectionPath, expectedNode);
+ _performEdit(edit!, collectionPath, expectedNode);
return nodeToRemove;
}
@@ -463,11 +451,8 @@
///
/// If [checkAlias] is `true`, throw [AliasError] if an aliased node is
/// encountered.
- YamlNode _traverse(Iterable<Object> path,
- {bool checkAlias = false, YamlNode Function() orElse}) {
- ArgumentError.checkNotNull(path, 'path');
- ArgumentError.checkNotNull(checkAlias, 'checkAlias');
-
+ YamlNode _traverse(Iterable<Object?> path,
+ {bool checkAlias = false, YamlNode Function()? orElse}) {
if (path.isEmpty) return _contents;
var currentNode = _contents;
@@ -481,14 +466,14 @@
}
if (currentNode is YamlList) {
- final list = currentNode as YamlList;
+ final list = currentNode;
if (!isValidIndex(keyOrIndex, list.length)) {
return _pathErrorOrElse(path, path.take(i + 1), list, orElse);
}
- currentNode = list.nodes[keyOrIndex];
+ currentNode = list.nodes[keyOrIndex as int];
} else if (currentNode is YamlMap) {
- final map = currentNode as YamlMap;
+ final map = currentNode;
if (!containsKey(map, keyOrIndex)) {
return _pathErrorOrElse(path, path.take(i + 1), map, orElse);
@@ -499,7 +484,7 @@
if (_aliases.contains(keyNode)) throw AliasError(path, keyNode);
}
- currentNode = map.nodes[keyNode];
+ currentNode = map.nodes[keyNode]!;
} else {
return _pathErrorOrElse(path, path.take(i + 1), currentNode, orElse);
}
@@ -512,16 +497,14 @@
/// Throws a [PathError] if [orElse] is not provided, returns the result
/// of invoking the [orElse] function otherwise.
- YamlNode _pathErrorOrElse(Iterable<Object> path, Iterable<Object> subPath,
- YamlNode parent, YamlNode Function() orElse) {
+ YamlNode _pathErrorOrElse(Iterable<Object?> path, Iterable<Object?> subPath,
+ YamlNode parent, YamlNode Function()? orElse) {
if (orElse == null) throw PathError(path, subPath, parent);
return orElse();
}
/// Asserts that [node] and none its children are aliases
- void _assertNoChildAlias(Iterable<Object> path, [YamlNode node]) {
- ArgumentError.checkNotNull(path, 'path');
-
+ void _assertNoChildAlias(Iterable<Object?> path, [YamlNode? node]) {
if (node == null) return _assertNoChildAlias(path, _traverse(path));
if (_aliases.contains(node)) throw AliasError(path, node);
@@ -551,10 +534,7 @@
/// Throws [ArgumentError] if the element at the given path is not a
/// [YamlList] or if the path is invalid. If [checkAlias] is `true`, and an
/// aliased node is encountered along [path], an [AliasError] will be thrown.
- YamlList _traverseToList(Iterable<Object> path, {bool checkAlias = false}) {
- ArgumentError.checkNotNull(path, 'path');
- ArgumentError.checkNotNull(checkAlias, 'checkAlias');
-
+ YamlList _traverseToList(Iterable<Object?> path, {bool checkAlias = false}) {
final possibleList = _traverse(path, checkAlias: true);
if (possibleList is YamlList) {
@@ -572,10 +552,7 @@
/// tree is equal to our expectations by deep equality of values. Throws an
/// [AssertionError] if the two trees do not match.
void _performEdit(
- SourceEdit edit, Iterable<Object> path, YamlNode expectedNode) {
- ArgumentError.checkNotNull(edit, 'edit');
- ArgumentError.checkNotNull(path, 'path');
-
+ SourceEdit edit, Iterable<Object?> path, YamlNode expectedNode) {
final expectedTree = _deepModify(_contents, path, [], expectedNode);
final initialYaml = _yaml;
_yaml = edit.apply(_yaml);
@@ -613,10 +590,8 @@
/// the whole tree.
///
/// [SourceSpan]s in this new tree are not guaranteed to be accurate.
- YamlNode _deepModify(YamlNode tree, Iterable<Object> path,
- Iterable<Object> subPath, YamlNode expectedNode) {
- ArgumentError.checkNotNull(path, 'path');
- ArgumentError.checkNotNull(tree, 'tree');
+ YamlNode _deepModify(YamlNode tree, Iterable<Object?> path,
+ Iterable<Object?> subPath, YamlNode expectedNode) {
RangeError.checkValueInInterval(subPath.length, 0, path.length);
if (path.length == subPath.length) return expectedNode;
@@ -628,7 +603,7 @@
throw PathError(path, subPath, tree);
}
- return wrapAsYamlNode([...tree.nodes]..[keyOrIndex] = _deepModify(
+ return wrapAsYamlNode([...tree.nodes]..[keyOrIndex as int] = _deepModify(
tree.nodes[keyOrIndex],
path,
path.take(subPath.length + 1),
diff --git a/lib/src/equality.dart b/lib/src/equality.dart
index 3190812..695a775 100644
--- a/lib/src/equality.dart
+++ b/lib/src/equality.dart
@@ -82,7 +82,7 @@
/// Returns a hashcode for [value] such that structures that are equal by
/// [deepEquals] will have the same hash code.
-int deepHashCode(Object value) {
+int deepHashCode(Object? value) {
if (value is Map) {
const equality = UnorderedIterableEquality();
return equality.hash(value.keys.map(deepHashCode)) ^
@@ -97,13 +97,13 @@
}
/// Returns the [YamlNode] corresponding to the provided [key].
-YamlNode getKeyNode(YamlMap map, Object key) {
+YamlNode getKeyNode(YamlMap map, Object? key) {
return map.nodes.keys.firstWhere((node) => deepEquals(node, key)) as YamlNode;
}
/// Returns the [YamlNode] after the [YamlNode] corresponding to the provided
/// [key].
-YamlNode getNextKeyNode(YamlMap map, Object key) {
+YamlNode? getNextKeyNode(YamlMap map, Object? key) {
final keyIterator = map.nodes.keys.iterator;
while (keyIterator.moveNext()) {
if (deepEquals(keyIterator.current, key) && keyIterator.moveNext()) {
@@ -116,11 +116,11 @@
/// Returns the key in [map] that is equal to the provided [key] by the notion
/// of deep equality.
-Object getKey(Map map, Object key) {
+Object? getKey(Map map, Object? key) {
return map.keys.firstWhere((k) => deepEquals(k, key));
}
/// Checks if [map] has any keys equal to the provided [key] by deep equality.
-bool containsKey(Map map, Object key) {
+bool containsKey(Map map, Object? key) {
return map.keys.where((node) => deepEquals(node, key)).isNotEmpty;
}
diff --git a/lib/src/errors.dart b/lib/src/errors.dart
index 4a58440..ca1b28a 100644
--- a/lib/src/errors.dart
+++ b/lib/src/errors.dart
@@ -19,15 +19,15 @@
@sealed
class PathError extends ArgumentError {
/// The full path that caused the error
- final Iterable<Object> path;
+ final Iterable<Object?> path;
/// The subpath that caused the error
- final Iterable<Object> subPath;
+ final Iterable<Object?> subPath;
/// The last element of [path] that could be traversed.
- YamlNode parent;
+ YamlNode? parent;
- PathError(this.path, this.subPath, this.parent, [String message])
+ PathError(this.path, this.subPath, this.parent, [String? message])
: super.value(subPath, 'path', message);
PathError.unexpected(this.path, String message)
@@ -62,7 +62,7 @@
@sealed
class AliasError extends UnsupportedError {
/// The path that caused the error
- final Iterable<Object> path;
+ final Iterable<Object?> path;
/// The anchor node of the alias
final YamlNode anchor;
diff --git a/lib/src/list_mutations.dart b/lib/src/list_mutations.dart
index f36fdf2..ef30fff 100644
--- a/lib/src/list_mutations.dart
+++ b/lib/src/list_mutations.dart
@@ -24,8 +24,6 @@
/// the effect of setting the element at [index] to [newValue] when re-parsed.
SourceEdit updateInList(
YamlEditor yamlEdit, YamlList list, int index, YamlNode newValue) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(list, 'list');
RangeError.checkValueInInterval(index, 0, list.length - 1);
final currValue = list.nodes[index];
@@ -72,9 +70,6 @@
/// Returns a [SourceEdit] describing the change to be made on [yaml] to achieve
/// the effect of appending [item] to the list.
SourceEdit appendIntoList(YamlEditor yamlEdit, YamlList list, YamlNode item) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(list, 'list');
-
if (list.style == CollectionStyle.FLOW) {
return _appendToFlowList(yamlEdit, list, item);
} else {
@@ -86,8 +81,6 @@
/// the effect of inserting [item] to the list at [index].
SourceEdit insertInList(
YamlEditor yamlEdit, YamlList list, int index, YamlNode item) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(list, 'list');
RangeError.checkValueInInterval(index, 0, list.length);
/// We call the append method if the user wants to append it to the end of the
@@ -106,9 +99,6 @@
/// Returns a [SourceEdit] describing the change to be made on [yaml] to achieve
/// the effect of removing the element at [index] when re-parsed.
SourceEdit removeInList(YamlEditor yamlEdit, YamlList list, int index) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(list, 'list');
-
final nodeToRemove = list.nodes[index];
if (list.style == CollectionStyle.FLOW) {
@@ -122,9 +112,6 @@
/// the effect of addition [item] into [nodes], noting that this is a flow list.
SourceEdit _appendToFlowList(
YamlEditor yamlEdit, YamlList list, YamlNode item) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(list, 'list');
-
final valueString = _formatNewFlow(list, item, true);
return SourceEdit(list.span.end.offset - 1, 0, valueString);
}
@@ -133,9 +120,6 @@
/// the effect of addition [item] into [nodes], noting that this is a block list.
SourceEdit _appendToBlockList(
YamlEditor yamlEdit, YamlList list, YamlNode item) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(list, 'list');
-
var formattedValue = _formatNewBlock(yamlEdit, list, item);
final yaml = yamlEdit.toString();
var offset = list.span.end.offset;
@@ -156,9 +140,6 @@
/// Formats [item] into a new node for block lists.
String _formatNewBlock(YamlEditor yamlEdit, YamlList list, YamlNode item) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(list, 'list');
-
final yaml = yamlEdit.toString();
final listIndentation = getListIndentation(yaml, list);
final newIndentation = listIndentation + getIndentation(yamlEdit);
@@ -175,9 +156,6 @@
/// Formats [item] into a new node for flow lists.
String _formatNewFlow(YamlList list, YamlNode item, [bool isLast = false]) {
- ArgumentError.checkNotNull(list, 'list');
- ArgumentError.checkNotNull(isLast, 'isLast');
-
var valueString = yamlEncodeFlowString(item);
if (list.isNotEmpty) {
if (isLast) {
@@ -197,8 +175,6 @@
/// [index] should be non-negative and less than or equal to [length].
SourceEdit _insertInBlockList(
YamlEditor yamlEdit, YamlList list, int index, YamlNode item) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(list, 'list');
RangeError.checkValueInInterval(index, 0, list.length);
if (index == list.length) return _appendToBlockList(yamlEdit, list, item);
@@ -220,8 +196,6 @@
/// [index] should be non-negative and less than or equal to [length].
SourceEdit _insertInFlowList(
YamlEditor yamlEdit, YamlList list, int index, YamlNode item) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(list, 'list');
RangeError.checkValueInInterval(index, 0, list.length);
if (index == list.length) return _appendToFlowList(yamlEdit, list, item);
@@ -244,8 +218,6 @@
/// [index] should be non-negative and less than or equal to [length].
SourceEdit _removeFromBlockList(
YamlEditor yamlEdit, YamlList list, YamlNode nodeToRemove, int index) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(list, 'list');
RangeError.checkValueInInterval(index, 0, list.length - 1);
var end = getContentSensitiveEnd(nodeToRemove);
@@ -321,8 +293,6 @@
/// [index] should be non-negative and less than or equal to [length].
SourceEdit _removeFromFlowList(
YamlEditor yamlEdit, YamlList list, YamlNode nodeToRemove, int index) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(list, 'list');
RangeError.checkValueInInterval(index, 0, list.length - 1);
final span = nodeToRemove.span;
diff --git a/lib/src/map_mutations.dart b/lib/src/map_mutations.dart
index 7e6b1c9..2084b59 100644
--- a/lib/src/map_mutations.dart
+++ b/lib/src/map_mutations.dart
@@ -24,10 +24,7 @@
/// Performs the string operation on [yaml] to achieve the effect of setting
/// the element at [key] to [newValue] when re-parsed.
SourceEdit updateInMap(
- YamlEditor yamlEdit, YamlMap map, Object key, YamlNode newValue) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(map, 'map');
-
+ YamlEditor yamlEdit, YamlMap map, Object? key, YamlNode newValue) {
if (!containsKey(map, key)) {
final keyNode = wrapAsYamlNode(key);
@@ -47,14 +44,9 @@
/// Performs the string operation on [yaml] to achieve the effect of removing
/// the element at [key] when re-parsed.
-SourceEdit removeInMap(YamlEditor yamlEdit, YamlMap map, Object key) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(map, 'map');
-
- if (!containsKey(map, key)) return null;
-
+SourceEdit removeInMap(YamlEditor yamlEdit, YamlMap map, Object? key) {
final keyNode = getKeyNode(map, key);
- final valueNode = map.nodes[keyNode];
+ final valueNode = map.nodes[keyNode]!;
if (map.style == CollectionStyle.FLOW) {
return _removeFromFlowMap(yamlEdit, map, keyNode, valueNode);
@@ -68,9 +60,6 @@
/// block map.
SourceEdit _addToBlockMap(
YamlEditor yamlEdit, YamlMap map, Object key, YamlNode newValue) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(map, 'map');
-
final yaml = yamlEdit.toString();
final newIndentation =
getMapIndentation(yaml, map) + getIndentation(yamlEdit);
@@ -120,9 +109,6 @@
/// map.
SourceEdit _addToFlowMap(
YamlEditor yamlEdit, YamlMap map, YamlNode keyNode, YamlNode newValue) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(map, 'map');
-
final keyString = yamlEncodeFlowString(keyNode);
final valueString = yamlEncodeFlowString(newValue);
@@ -147,10 +133,7 @@
/// the value at [key] with [newValue] when reparsed, bearing in mind that this
/// is a block map.
SourceEdit _replaceInBlockMap(
- YamlEditor yamlEdit, YamlMap map, Object key, YamlNode newValue) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(map, 'map');
-
+ YamlEditor yamlEdit, YamlMap map, Object? key, YamlNode newValue) {
final yaml = yamlEdit.toString();
final lineEnding = getLineEnding(yaml);
final newIndentation =
@@ -167,7 +150,7 @@
/// +1 accounts for the colon
final start = keyNode.span.end.offset + 1;
- var end = getContentSensitiveEnd(map.nodes[key]);
+ var end = getContentSensitiveEnd(map.nodes[key]!);
/// `package:yaml` parses empty nodes in a way where the start/end of the
/// empty value node is the end of the key node, so we have to adjust for
@@ -181,11 +164,8 @@
/// the value at [key] with [newValue] when reparsed, bearing in mind that this
/// is a flow map.
SourceEdit _replaceInFlowMap(
- YamlEditor yamlEdit, YamlMap map, Object key, YamlNode newValue) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(map, 'map');
-
- final valueSpan = map.nodes[key].span;
+ YamlEditor yamlEdit, YamlMap map, Object? key, YamlNode newValue) {
+ final valueSpan = map.nodes[key]!.span;
final valueString = yamlEncodeFlowString(newValue);
return SourceEdit(valueSpan.start.offset, valueSpan.length, valueString);
@@ -195,11 +175,6 @@
/// the [key] from the map, bearing in mind that this is a block map.
SourceEdit _removeFromBlockMap(
YamlEditor yamlEdit, YamlMap map, YamlNode keyNode, YamlNode valueNode) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(map, 'map');
- ArgumentError.checkNotNull(keyNode, 'keyNode');
- ArgumentError.checkNotNull(valueNode, 'valueNode');
-
final keySpan = keyNode.span;
var end = getContentSensitiveEnd(valueNode);
final yaml = yamlEdit.toString();
@@ -247,11 +222,6 @@
/// the [key] from the map, bearing in mind that this is a flow map.
SourceEdit _removeFromFlowMap(
YamlEditor yamlEdit, YamlMap map, YamlNode keyNode, YamlNode valueNode) {
- ArgumentError.checkNotNull(yamlEdit, 'yamlEdit');
- ArgumentError.checkNotNull(map, 'map');
- ArgumentError.checkNotNull(keyNode, 'keyNode');
- ArgumentError.checkNotNull(valueNode, 'valueNode');
-
var start = keyNode.span.start.offset;
var end = valueNode.span.end.offset;
final yaml = yamlEdit.toString();
diff --git a/lib/src/source_edit.dart b/lib/src/source_edit.dart
index f8e6ab9..7721ba9 100644
--- a/lib/src/source_edit.dart
+++ b/lib/src/source_edit.dart
@@ -43,9 +43,6 @@
SourceEdit._(offset, length, replacement);
SourceEdit._(this.offset, this.length, this.replacement) {
- ArgumentError.checkNotNull(offset, 'offset');
- ArgumentError.checkNotNull(length, 'length');
- ArgumentError.checkNotNull(replacement, 'replacement');
RangeError.checkNotNegative(offset);
RangeError.checkNotNegative(length);
}
@@ -77,8 +74,6 @@
/// final sourceEdit = SourceEdit.fromJson(edit);
/// ```
factory SourceEdit.fromJson(Map<String, dynamic> json) {
- ArgumentError.checkNotNull(json, 'json');
-
if (json is Map) {
final offset = json['offset'];
final length = json['length'];
@@ -130,9 +125,6 @@
/// Language"
/// ```
static String applyAll(String original, Iterable<SourceEdit> edits) {
- ArgumentError.checkNotNull(original, 'original');
- ArgumentError.checkNotNull(edits, 'edits');
-
return edits.fold(original, (current, edit) => edit.apply(current));
}
@@ -146,8 +138,6 @@
/// print(edit.apply(originalString)); // 'foo: barbar'
/// ```
String apply(String original) {
- ArgumentError.checkNotNull(original, 'original');
-
return original.replaceRange(offset, offset + length, replacement);
}
}
diff --git a/lib/src/strings.dart b/lib/src/strings.dart
index 65bdac5..1143d1b 100644
--- a/lib/src/strings.dart
+++ b/lib/src/strings.dart
@@ -22,7 +22,7 @@
/// an escape sequence, it can only be detected when in a double-quoted
/// sequence. Plain strings may also be misinterpreted by the YAML parser (e.g.
/// ' null').
-String _tryYamlEncodePlain(Object value) {
+String _tryYamlEncodePlain(Object? value) {
if (value is YamlNode) {
AssertionError(
'YamlNodes should not be passed directly into getSafeString!');
@@ -50,8 +50,6 @@
/// Checks if [string] has unprintable characters according to
/// [unprintableCharCodes].
bool _hasUnprintableCharacters(String string) {
- ArgumentError.checkNotNull(string, 'string');
-
final codeUnits = string.codeUnits;
for (final key in unprintableCharCodes.keys) {
@@ -66,8 +64,6 @@
///
/// See 5.7 Escaped Characters https://yaml.org/spec/1.2/spec.html#id2776092
String _yamlEncodeDoubleQuoted(String string) {
- ArgumentError.checkNotNull(string, 'string');
-
final buffer = StringBuffer();
for (final codeUnit in string.codeUnits) {
if (doubleQuoteEscapeChars[codeUnit] != null) {
@@ -86,8 +82,6 @@
/// It is important that we ensure that [string] is free of unprintable
/// characters by calling [assertValidScalar] before invoking this function.
String _tryYamlEncodeSingleQuoted(String string) {
- ArgumentError.checkNotNull(string, 'string');
-
final result = string.replaceAll('\'', '\'\'');
return '\'$result\'';
}
@@ -97,10 +91,6 @@
/// It is important that we ensure that [string] is free of unprintable
/// characters by calling [assertValidScalar] before invoking this function.
String _tryYamlEncodeFolded(String string, int indentation, String lineEnding) {
- ArgumentError.checkNotNull(string, 'string');
- ArgumentError.checkNotNull(indentation, 'indentation');
- ArgumentError.checkNotNull(lineEnding, 'lineEnding');
-
String result;
final trimmedString = string.trimRight();
@@ -126,10 +116,6 @@
/// characters by calling [assertValidScalar] before invoking this function.
String _tryYamlEncodeLiteral(
String string, int indentation, String lineEnding) {
- ArgumentError.checkNotNull(string, 'string');
- ArgumentError.checkNotNull(indentation, 'indentation');
- ArgumentError.checkNotNull(lineEnding, 'lineEnding');
-
final result = '|-\n$string';
/// Assumes the user did not try to account for windows documents by using
@@ -175,9 +161,6 @@
/// options.
String yamlEncodeBlockScalar(
YamlNode value, int indentation, String lineEnding) {
- ArgumentError.checkNotNull(indentation, 'indentation');
- ArgumentError.checkNotNull(lineEnding, 'lineEnding');
-
if (value is YamlScalar) {
assertValidScalar(value.value);
@@ -243,9 +226,6 @@
/// If [value] is a [YamlNode], we respect its [style] parameter.
String yamlEncodeBlockString(
YamlNode value, int indentation, String lineEnding) {
- ArgumentError.checkNotNull(indentation, 'indentation');
- ArgumentError.checkNotNull(lineEnding, 'lineEnding');
-
const additionalIndentation = 2;
if (!isBlockNode(value)) return yamlEncodeFlowString(value);
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index c0d70bf..5550c75 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -23,8 +23,6 @@
/// This function is also capable of detecting if non-printable characters are in
/// [string].
bool isDangerousString(String string) {
- ArgumentError.checkNotNull(string, 'string');
-
try {
if (loadYamlNode(string).value != string) {
return true;
@@ -43,7 +41,7 @@
/// Asserts that [value] is a valid scalar according to YAML.
///
/// A valid scalar is a number, String, boolean, or null.
-void assertValidScalar(Object value) {
+void assertValidScalar(Object? value) {
if (value is num || value is String || value is bool || value == null) {
return;
}
@@ -56,8 +54,6 @@
/// [ScalarStyle.ANY] and [CollectionStyle.ANY] are considered to be block styling
/// by default for maximum flexibility.
bool isBlockNode(YamlNode node) {
- ArgumentError.checkNotNull(node, 'node');
-
if (node is YamlScalar) {
if (node.style == ScalarStyle.LITERAL ||
node.style == ScalarStyle.FOLDED ||
@@ -79,8 +75,6 @@
/// Returns the content sensitive ending offset of [yamlNode] (i.e. where the last
/// meaningful content happens)
int getContentSensitiveEnd(YamlNode yamlNode) {
- ArgumentError.checkNotNull(yamlNode, 'yamlNode');
-
if (yamlNode is YamlList) {
if (yamlNode.style == CollectionStyle.FLOW) {
return yamlNode.span.end.offset;
@@ -102,7 +96,7 @@
bool isCollection(Object item) => item is Map || item is List;
/// Checks if [index] is [int], >=0, < [length]
-bool isValidIndex(Object index, int length) {
+bool isValidIndex(Object? index, int length) {
return index is int && index >= 0 && index < length;
}
@@ -121,7 +115,7 @@
///
/// Mainly used with [wrapAsYamlNode] to allow for a reasonable
/// implementation of [SourceSpan.message].
-SourceSpan shellSpan(Object sourceUrl) {
+SourceSpan shellSpan(Object? sourceUrl) {
final shellSourceLocation = SourceLocation(0, sourceUrl: sourceUrl);
return SourceSpanBase(shellSourceLocation, shellSourceLocation, '');
}
@@ -140,8 +134,6 @@
///
/// Returns the length of [map] if the keys in [map] are not in alphabetical order.
int getMapInsertionIndex(YamlMap map, Object newKey) {
- ArgumentError.checkNotNull(map, 'map');
-
final keys = map.nodes.keys.map((k) => k.toString()).toList();
for (var i = 1; i < keys.length; i++) {
@@ -150,7 +142,8 @@
}
}
- final insertionIndex = keys.indexWhere((key) => key.compareTo(newKey) > 0);
+ final insertionIndex =
+ keys.indexWhere((key) => key.compareTo(newKey as String) > 0);
if (insertionIndex != -1) return insertionIndex;
@@ -158,7 +151,7 @@
}
/// Returns the [style] property of [target], if it is a [YamlNode]. Otherwise return null.
-Object getStyle(Object target) {
+Object? getStyle(Object target) {
if (target is YamlNode) {
return (target as dynamic).style;
}
@@ -175,7 +168,7 @@
/// candidates, we choose the candidate closest to the start of [yaml].
int getIndentation(YamlEditor editor) {
final node = editor.parseAt([]);
- Iterable<YamlNode> children;
+ Iterable<YamlNode>? children;
var indentation = 2;
if (node is YamlMap && node.style == CollectionStyle.BLOCK) {
@@ -205,8 +198,6 @@
///
/// Throws [UnsupportedError] if an empty block map is passed in.
int getListIndentation(String yaml, YamlList list) {
- ArgumentError.checkNotNull(list, 'list');
-
if (list.style == CollectionStyle.FLOW) return 0;
/// An empty block map doesn't really exist.
@@ -226,8 +217,6 @@
/// Gets the indentation level of [map]. This is 0 if it is a flow map,
/// but returns the number of spaces before the keys for block maps.
int getMapIndentation(String yaml, YamlMap map) {
- ArgumentError.checkNotNull(map, 'map');
-
if (map.style == CollectionStyle.FLOW) return 0;
/// An empty block map doesn't really exist.
diff --git a/lib/src/wrap.dart b/lib/src/wrap.dart
index f82bd72..e95c43f 100644
--- a/lib/src/wrap.dart
+++ b/lib/src/wrap.dart
@@ -24,14 +24,12 @@
/// Returns a new [YamlMap] constructed by applying [update] onto the [nodes]
/// of this [YamlMap].
YamlMap updatedYamlMap(YamlMap map, Function(Map) update) {
- ArgumentError.checkNotNull(map, 'map');
-
final dummyMap = deepEqualsMap();
dummyMap.addAll(map.nodes);
update(dummyMap);
- return wrapAsYamlNode(dummyMap);
+ return wrapAsYamlNode(dummyMap) as YamlMap;
}
/// Wraps [value] into a [YamlNode].
@@ -43,7 +41,7 @@
///
/// If a [YamlNode] is passed in, no further wrapping will be done, and the
/// [collectionStyle]/[scalarStyle] will not be applied.
-YamlNode wrapAsYamlNode(Object value,
+YamlNode wrapAsYamlNode(Object? value,
{CollectionStyle collectionStyle = CollectionStyle.ANY,
ScalarStyle scalarStyle = ScalarStyle.ANY}) {
if (value is YamlScalar) {
@@ -65,15 +63,12 @@
return value;
} else if (value is Map) {
- ArgumentError.checkNotNull(collectionStyle, 'collectionStyle');
return YamlMapWrap(value, collectionStyle: collectionStyle);
} else if (value is List) {
- ArgumentError.checkNotNull(collectionStyle, 'collectionStyle');
return YamlListWrap(value, collectionStyle: collectionStyle);
} else {
assertValidScalar(value);
- ArgumentError.checkNotNull(scalarStyle, 'scalarStyle');
return YamlScalarWrap(value, style: scalarStyle);
}
}
@@ -91,10 +86,8 @@
@override
final dynamic value;
- YamlScalarWrap(this.value, {this.style = ScalarStyle.ANY, Object sourceUrl})
- : span = shellSpan(sourceUrl) {
- ArgumentError.checkNotNull(style, 'scalarStyle');
- }
+ YamlScalarWrap(this.value, {this.style = ScalarStyle.ANY, Object? sourceUrl})
+ : span = shellSpan(sourceUrl);
@override
String toString() => value.toString();
@@ -117,9 +110,7 @@
factory YamlMapWrap(Map dartMap,
{CollectionStyle collectionStyle = CollectionStyle.ANY,
- Object sourceUrl}) {
- ArgumentError.checkNotNull(collectionStyle, 'collectionStyle');
-
+ Object? sourceUrl}) {
final wrappedMap = deepEqualsMap<dynamic, YamlNode>();
for (final entry in dartMap.entries) {
@@ -133,12 +124,12 @@
}
YamlMapWrap._(this.nodes,
- {CollectionStyle style = CollectionStyle.ANY, Object sourceUrl})
+ {CollectionStyle style = CollectionStyle.ANY, Object? sourceUrl})
: span = shellSpan(sourceUrl),
style = nodes.isEmpty ? CollectionStyle.FLOW : style;
@override
- dynamic operator [](Object key) => nodes[key]?.value;
+ dynamic operator [](Object? key) => nodes[key]?.value;
@override
Iterable get keys => nodes.keys.map((node) => node.value);
@@ -170,16 +161,14 @@
factory YamlListWrap(List dartList,
{CollectionStyle collectionStyle = CollectionStyle.ANY,
- Object sourceUrl}) {
- ArgumentError.checkNotNull(collectionStyle, 'collectionStyle');
-
+ Object? sourceUrl}) {
final wrappedList = dartList.map(wrapAsYamlNode).toList();
return YamlListWrap._(wrappedList,
style: collectionStyle, sourceUrl: sourceUrl);
}
YamlListWrap._(this.nodes,
- {CollectionStyle style = CollectionStyle.ANY, Object sourceUrl})
+ {CollectionStyle style = CollectionStyle.ANY, Object? sourceUrl})
: span = shellSpan(sourceUrl),
style = nodes.isEmpty ? CollectionStyle.FLOW : style;
diff --git a/pubspec.yaml b/pubspec.yaml
index d175b67..91ef188 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -8,10 +8,10 @@
collection: ^1.14.11
meta: ^1.1.8
source_span: ^1.7.0
- yaml: ^2.2.1
+ yaml: ^3.1.0
dev_dependencies:
path: ^1.6.2
pedantic: ^1.9.0
test: ^1.14.4
environment:
- sdk: ">=2.4.0 <3.0.0"
+ sdk: ">=2.12.0-0 <3.0.0"
diff --git a/test/append_test.dart b/test/append_test.dart
index 212c749..4b80ff0 100644
--- a/test/append_test.dart
+++ b/test/append_test.dart
@@ -49,6 +49,28 @@
expectYamlBuilderValue(doc, [0, 1, 2, 3, 4]);
});
+ test('null path', () {
+ final doc = YamlEditor('''
+~:
+ - 0
+ - 1
+ - 2
+ - 3
+''');
+ doc.appendToList([null], 4);
+ expect(doc.toString(), equals('''
+~:
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+'''));
+ expectYamlBuilderValue(doc, {
+ null: [0, 1, 2, 3, 4]
+ });
+ });
+
test('element to simple block list ', () {
final doc = YamlEditor('''
- 0
@@ -123,7 +145,7 @@
test('nested', () {
final yamlEditor = YamlEditor('''
a:
- 1:
+ 1:
- null
2: null
''');
@@ -131,7 +153,7 @@
expect(yamlEditor.toString(), equals('''
a:
- 1:
+ 1:
- null
- false
2: null
@@ -147,6 +169,13 @@
expectYamlBuilderValue(doc, [0, 1, 2, 3]);
});
+ test('null value', () {
+ final doc = YamlEditor('[0, 1, 2]');
+ doc.appendToList([], null);
+ expect(doc.toString(), equals('[0, 1, 2, null]'));
+ expectYamlBuilderValue(doc, [0, 1, 2, null]);
+ });
+
test('empty ', () {
final doc = YamlEditor('[]');
doc.appendToList([], 0);
diff --git a/test/golden_test.dart b/test/golden_test.dart
index 7715069..305aa51 100644
--- a/test/golden_test.dart
+++ b/test/golden_test.dart
@@ -29,7 +29,7 @@
final packageUri = await Isolate.resolvePackageUri(
Uri.parse('package:yaml_edit/yaml_edit.dart'));
- final testdataUri = packageUri.resolve('../test/testdata/');
+ final testdataUri = packageUri!.resolve('../test/testdata/');
final inputDirectory = Directory.fromUri(testdataUri.resolve('input/'));
final goldDirectoryUri = testdataUri.resolve('output/');
diff --git a/test/parse_test.dart b/test/parse_test.dart
index ea2ae57..a743b90 100644
--- a/test/parse_test.dart
+++ b/test/parse_test.dart
@@ -50,11 +50,11 @@
});
group('orElse provides a default value', () {
- test('simple example with null return ', () {
+ test('simple example with null node return ', () {
final doc = YamlEditor('{a: {d: 4}, c: ~}');
- final result = doc.parseAt(['b'], orElse: () => null);
+ final result = doc.parseAt(['b'], orElse: () => wrapAsYamlNode(null));
- expect(result, equals(null));
+ expect(result.value, equals(null));
});
test('simple example with map return', () {
diff --git a/test/prepend_test.dart b/test/prepend_test.dart
index 52256ef..ab69fc2 100644
--- a/test/prepend_test.dart
+++ b/test/prepend_test.dart
@@ -39,6 +39,13 @@
expectYamlBuilderValue(doc, [0, 1, 2]);
});
+ test('null value', () {
+ final doc = YamlEditor('[1, 2]');
+ doc.prependToList([], null);
+ expect(doc.toString(), equals('[null, 1, 2]'));
+ expectYamlBuilderValue(doc, [null, 1, 2]);
+ });
+
test('with spaces (1)', () {
final doc = YamlEditor('[ 1 , 2 ]');
doc.prependToList([], 0);
diff --git a/test/random_test.dart b/test/random_test.dart
index a334335..2b5af99 100644
--- a/test/random_test.dart
+++ b/test/random_test.dart
@@ -79,7 +79,7 @@
/// Maximum depth of random YAML collection generated.
final int maxDepth;
- _Generator({int seed, this.maxDepth = 5}) : r = Random(seed ?? 42);
+ _Generator({int? seed, this.maxDepth = 5}) : r = Random(seed ?? 42);
int nextInt([int max = maxInt]) => r.nextInt(max);
@@ -107,7 +107,7 @@
}
/// Generates a new scalar recognizable by YAML.
- Object nextScalar() {
+ Object? nextScalar() {
final typeIndex = nextInt(5);
switch (typeIndex) {
@@ -125,7 +125,8 @@
}
YamlScalar nextYamlScalar() {
- return wrapAsYamlNode(nextScalar(), scalarStyle: nextScalarStyle());
+ return wrapAsYamlNode(nextScalar(), scalarStyle: nextScalarStyle())
+ as YamlScalar;
}
/// Generates the next [YamlList], with the current [depth].
@@ -137,7 +138,8 @@
list.add(nextYamlNode(depth + 1));
}
- return wrapAsYamlNode(list, collectionStyle: nextCollectionStyle());
+ return wrapAsYamlNode(list, collectionStyle: nextCollectionStyle())
+ as YamlList;
}
/// Generates the next [YamlList], with the current [depth].
@@ -149,7 +151,8 @@
nodes[nextYamlNode(depth + 1)] = nextYamlScalar();
}
- return wrapAsYamlNode(nodes, collectionStyle: nextCollectionStyle());
+ return wrapAsYamlNode(nodes, collectionStyle: nextCollectionStyle())
+ as YamlMap;
}
/// Returns a [YamlNode], with it being a [YamlScalar] 80% of the time, a
@@ -217,7 +220,7 @@
break;
case YamlModificationMethod.splice:
args.add(nextInt(node.length + 1));
- args.add(nextInt(node.length + 1 - args[0]));
+ args.add(nextInt(node.length + 1 - args[0] as int));
args.add(nextYamlList(0));
editor.spliceList(path, args[0], args[1], args[2]);
break;
@@ -240,7 +243,7 @@
editor.update(path, value);
return;
}
- } catch (error) {
+ } catch (error, stacktrace) {
print('''
Failed to call $method on:
$initialString
@@ -250,7 +253,9 @@
$path
Error Details:
-${error.message}
+${error}
+
+${stacktrace}
''');
rethrow;
}
@@ -262,8 +267,8 @@
///
/// At every node, we return the path to the node if the node has no children.
/// Otherwise, we return at a 50% chance, or traverse to one random child.
- List<Object> findPath(YamlEditor editor) {
- final path = [];
+ List<Object?> findPath(YamlEditor editor) {
+ final path = <Object?>[];
// 50% chance of stopping at the collection
while (nextBool()) {
diff --git a/test/remove_test.dart b/test/remove_test.dart
index adf4338..3ed2fed 100644
--- a/test/remove_test.dart
+++ b/test/remove_test.dart
@@ -39,6 +39,15 @@
expect(() => doc.remove(['d']), throwsPathError);
});
+ test('PathError if collectionPath is invalid in nested path', () {
+ final doc = YamlEditor('''
+a:
+ b: 'foo'
+''');
+
+ expect(() => doc.remove(['d']), throwsPathError);
+ });
+
test('PathError if collectionPath is invalid - list', () {
final doc = YamlEditor('''
[1, 2, 3]
@@ -46,6 +55,30 @@
expect(() => doc.remove([4]), throwsPathError);
});
+
+ test('PathError in list if using a non-integer as index', () {
+ final doc = YamlEditor("{ a: ['b', 'c'] }");
+ expect(() => doc.remove(['a', 'b']), throwsPathError);
+ });
+
+ test('PathError if path is invalid', () {
+ final doc = YamlEditor("{ a: ['b', 'c'] }");
+ expect(() => doc.remove(['a', 0, '1']), throwsPathError);
+ });
+ });
+
+ group('returns', () {
+ test('returns the removed node when successful', () {
+ final doc = YamlEditor('{ a: { b: foo } }');
+ final node = doc.remove(['a', 'b']);
+ expect(node.value, equals('foo'));
+ });
+
+ test('returns null-value node when doc is empty and path is empty', () {
+ final doc = YamlEditor('');
+ final node = doc.remove([]);
+ expect(node.value, equals(null));
+ });
});
test('empty path should clear string', () {
@@ -75,7 +108,7 @@
test('empty value', () {
final doc = YamlEditor('''
a: 1
-b:
+b:
c: 3
''');
doc.remove(['b']);
@@ -88,7 +121,7 @@
test('empty value (2)', () {
final doc = YamlEditor('''
- a: 1
- b:
+ b:
c: 3
''');
doc.remove([0, 'b']);
@@ -101,7 +134,7 @@
test('empty value (3)', () {
final doc = YamlEditor('''
- a: 1
- b:
+ b:
c: 3
''');
@@ -143,14 +176,14 @@
test('final element in nested map', () {
final doc = YamlEditor('''
-a:
+a:
aa: 11
bb: 22
b: 2
''');
doc.remove(['a', 'bb']);
expect(doc.toString(), equals('''
-a:
+a:
aa: 11
b: 2
'''));
@@ -181,7 +214,7 @@
test('nested', () {
final doc = YamlEditor('''
a: 1
-b:
+b:
d: 4
e: 5
c: 3
@@ -189,7 +222,7 @@
doc.remove(['b', 'd']);
expect(doc.toString(), equals('''
a: 1
-b:
+b:
e: 5
c: 3
'''));
@@ -250,7 +283,7 @@
test('empty value', () {
final doc = YamlEditor('''
- 0
--
+-
- 2
''');
doc.remove([1]);
@@ -272,13 +305,13 @@
test('last element should return flow empty list (2)', () {
final doc = YamlEditor('''
-a:
+a:
- 1
b: [3]
''');
doc.remove(['a', 0]);
expect(doc.toString(), equals('''
-a:
+a:
[]
b: [3]
'''));
@@ -286,16 +319,16 @@
test('last element should return flow empty list (3)', () {
final doc = YamlEditor('''
-a:
+a:
- 1
-b:
+b:
- 3
''');
doc.remove(['a', 0]);
expect(doc.toString(), equals('''
-a:
+a:
[]
-b:
+b:
- 3
'''));
});
@@ -450,12 +483,12 @@
test('nested list (5)', () {
final doc = YamlEditor('''
- - 0
- -
+ -
1
''');
doc.remove([0, 0]);
expect(doc.toString(), equals('''
-- -
+- -
1
'''));
expectYamlBuilderValue(doc, [
@@ -467,13 +500,13 @@
final doc = YamlEditor('''
- - 0 # -
# -
- -
+ -
1
''');
doc.remove([0, 0]);
expect(doc.toString(), equals('''
- # -
- -
+ -
1
'''));
expectYamlBuilderValue(doc, [
@@ -499,14 +532,14 @@
test('nested map (2)', () {
final doc = YamlEditor('''
-- a:
+- a:
- 0
- 1
c: d
''');
doc.remove([0, 'a', 1]);
expect(doc.toString(), equals('''
-- a:
+- a:
- 0
c: d
'''));
diff --git a/test/test_case.dart b/test/test_case.dart
index 58bab5f..aa80d9e 100644
--- a/test/test_case.dart
+++ b/test/test_case.dart
@@ -81,9 +81,9 @@
final Uri goldenUri;
final List<String> states = [];
- String info;
- YamlEditor yamlBuilder;
- List<_YamlModification> modifications;
+ late String info;
+ late YamlEditor yamlBuilder;
+ late List<_YamlModification> modifications;
String inputLineEndings = '\n';
@@ -223,37 +223,40 @@
/// Converts a [YamlNode] into a Dart object.
dynamic _getValueFromYamlNode(YamlNode node) {
- switch (node.runtimeType) {
- case YamlList:
- return _getValueFromYamlList(node);
- case YamlMap:
- return _getValueFromYamlMap(node);
- default:
- return node.value;
+ if (node is YamlList) {
+ return _getValueFromYamlList(node);
}
+ if (node is YamlMap) {
+ return _getValueFromYamlMap(node);
+ }
+ return node.value;
+}
+
+List<T> _onlyType<T>(List<dynamic> rawPath) {
+ return rawPath.whereType<T>().toList();
}
/// Converts the list of modifications from the raw input to [_YamlModification]
/// objects.
List<_YamlModification> _parseModifications(List<dynamic> modifications) {
return modifications.map((mod) {
- Object value;
- int index;
- int deleteCount;
+ Object? value;
+ var index = 0;
+ var deleteCount = 0;
final method = _getModificationMethod(mod[0] as String);
- final path = mod[1] as List;
+ final path = mod[1];
if (method == YamlModificationMethod.appendTo ||
method == YamlModificationMethod.update ||
method == YamlModificationMethod.prependTo) {
value = mod[2];
} else if (method == YamlModificationMethod.insert) {
- index = mod[2];
+ index = mod[2] as int;
value = mod[3];
} else if (method == YamlModificationMethod.splice) {
- index = mod[2];
- deleteCount = mod[3];
+ index = mod[2] as int;
+ deleteCount = mod[3] as int;
if (mod[4] is! List) {
throw ArgumentError('Invalid array ${mod[4]} used in splice');
@@ -292,7 +295,7 @@
/// Class representing an abstract YAML modification to be performed
class _YamlModification {
final YamlModificationMethod method;
- final List<dynamic> path;
+ final List<Object?> path;
final int index;
final dynamic value;
final int deleteCount;
diff --git a/test/test_utils.dart b/test/test_utils.dart
index a87b18d..9f030f1 100644
--- a/test/test_utils.dart
+++ b/test/test_utils.dart
@@ -31,7 +31,7 @@
}
/// Asserts that [builder] has the same internal value as [expected].
-void expectDeepEquals(Object actual, Object expected) {
+void expectDeepEquals(Object? actual, Object expected) {
expect(
actual, predicate((actual) => deepEquals(actual, expected), '$expected'));
}
diff --git a/test/update_test.dart b/test/update_test.dart
index 685d6bd..64a9b6b 100644
--- a/test/update_test.dart
+++ b/test/update_test.dart
@@ -34,6 +34,11 @@
final doc = YamlEditor("- YAML Ain't Markup Language");
expect(() => doc.update([0, 'a'], 'a'), throwsPathError);
});
+
+ test('PathError in list if using a non-integer as index', () {
+ final doc = YamlEditor("{ a: ['b', 'c'] }");
+ expect(() => doc.update(['a', 'b'], 'x'), throwsPathError);
+ });
});
group('works on top-level', () {