Change AliasError to AliasException (dart-lang/yaml_edit#57)

diff --git a/pkgs/yaml_edit/CHANGELOG.md b/pkgs/yaml_edit/CHANGELOG.md
index d376b7c..d732b1a 100644
--- a/pkgs/yaml_edit/CHANGELOG.md
+++ b/pkgs/yaml_edit/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 2.2.0
+- `AliasError` is changed to `AliasException` and exposed in the public API.
+
+  All node-mutating methods on `YamlEditor`, i.e. `update()`, `appendToList()`,
+  `prependToList()`, `insertIntoList()`, `spliceList()`, `remove()` will now
+  throw an exception instead of an error when encountering an alias on the path
+  to modify.
+
+  This allows catching and handling when this is happening.
+
 ## 2.1.1
 
 - Require Dart 2.19
diff --git a/pkgs/yaml_edit/lib/src/editor.dart b/pkgs/yaml_edit/lib/src/editor.dart
index d56e2fa..9947d8f 100644
--- a/pkgs/yaml_edit/lib/src/editor.dart
+++ b/pkgs/yaml_edit/lib/src/editor.dart
@@ -199,6 +199,8 @@
   ///
   /// Throws a [ArgumentError] if [path] is invalid.
   ///
+  /// Throws an [AliasException] if a node on [path] is an alias or anchor.
+  ///
   /// **Example:** (using [update])
   /// ```dart
   /// final doc = YamlEditor('''
@@ -279,6 +281,8 @@
   /// Throws a [ArgumentError] if the element at the given path is not a
   /// [YamlList] or if the path is invalid.
   ///
+  /// Throws an [AliasException] if a node on [path] is an alias or anchor.
+  ///
   /// **Example:**
   /// ```dart
   /// final doc = YamlEditor('[0, 1]');
@@ -295,6 +299,8 @@
   /// Throws a [ArgumentError] if the element at the given path is not a
   /// [YamlList] or if the path is invalid.
   ///
+  /// Throws an [AliasException] if a node on [path] is an alias or anchor.
+  ///
   /// **Example:**
   /// ```dart
   /// final doc = YamlEditor('[1, 2]');
@@ -311,6 +317,8 @@
   /// Throws a [ArgumentError] if the element at the given path is not a
   /// [YamlList] or if the path is invalid.
   ///
+  /// Throws an [AliasException] if a node on [path] is an alias or anchor.
+  ///
   /// **Example:**
   /// ```dart
   /// final doc = YamlEditor('[0, 2]');
@@ -340,6 +348,8 @@
   /// Throws a [ArgumentError] if the element at the given path is not a
   /// [YamlList] or if the path is invalid.
   ///
+  /// Throws an [AliasException] if a node on [path] is an alias or anchor.
+  ///
   /// **Example:**
   /// ```dart
   /// final doc = YamlEditor('[Jan, March, April, June]');
@@ -375,7 +385,9 @@
   /// Removes the node at [path]. Comments "belonging" to the node will be
   /// removed while surrounding comments will be left untouched.
   ///
-  /// Throws a [ArgumentError] if [path] is invalid.
+  /// Throws an [ArgumentError] if [path] is invalid.
+  ///
+  /// Throws an [AliasException] if a node on [path] is an alias or anchor.
   ///
   /// **Example:**
   /// ```dart
@@ -441,7 +453,7 @@
   ///
   /// If [orElse] is omitted, it defaults to throwing a [PathError].
   ///
-  /// If [checkAlias] is `true`, throw [AliasError] if an aliased node is
+  /// If [checkAlias] is `true`, throw [AliasException] if an aliased node is
   /// encountered.
   YamlNode _traverse(Iterable<Object?> path,
       {bool checkAlias = false, YamlNode Function()? orElse}) {
@@ -454,7 +466,7 @@
       final keyOrIndex = pathList[i];
 
       if (checkAlias && _aliases.contains(currentNode)) {
-        throw AliasError(path, currentNode);
+        throw AliasException(path, currentNode);
       }
 
       if (currentNode is YamlList) {
@@ -473,7 +485,7 @@
         final keyNode = getKeyNode(map, keyOrIndex);
 
         if (checkAlias) {
-          if (_aliases.contains(keyNode)) throw AliasError(path, keyNode);
+          if (_aliases.contains(keyNode)) throw AliasException(path, keyNode);
         }
 
         currentNode = map.nodes[keyNode]!;
@@ -498,7 +510,7 @@
   /// Asserts that [node] and none its children are aliases
   void _assertNoChildAlias(Iterable<Object?> path, [YamlNode? node]) {
     if (node == null) return _assertNoChildAlias(path, _traverse(path));
-    if (_aliases.contains(node)) throw AliasError(path, node);
+    if (_aliases.contains(node)) throw AliasException(path, node);
 
     if (node is YamlScalar) return;
 
@@ -514,7 +526,7 @@
       for (var i = 0; i < node.length; i++) {
         final updatedPath = [...path, keyList[i]];
         if (_aliases.contains(keyList[i])) {
-          throw AliasError(path, keyList[i] as YamlNode);
+          throw AliasException(path, keyList[i] as YamlNode);
         }
         _assertNoChildAlias(updatedPath, node.nodes[keyList[i]]);
       }
@@ -527,9 +539,10 @@
   ///
   /// 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.
+  /// aliased node is encountered along [path], an [AliasException] will be
+  /// thrown.
   YamlList _traverseToList(Iterable<Object?> path, {bool checkAlias = false}) {
-    final possibleList = _traverse(path, checkAlias: true);
+    final possibleList = _traverse(path, checkAlias: checkAlias);
 
     if (possibleList is YamlList) {
       return possibleList;
diff --git a/pkgs/yaml_edit/lib/src/errors.dart b/pkgs/yaml_edit/lib/src/errors.dart
index a07a11f..51c6243 100644
--- a/pkgs/yaml_edit/lib/src/errors.dart
+++ b/pkgs/yaml_edit/lib/src/errors.dart
@@ -41,7 +41,7 @@
   }
 }
 
-/// Error thrown when the path contains an alias along the way.
+/// Exception thrown when the path contains an alias along the way.
 ///
 /// When a path contains an aliased node, the behavior becomes less well-defined
 /// because we cannot be certain if the user wishes for the change to
@@ -50,14 +50,14 @@
 /// the detection that our change will impact an alias, and we do not intend
 /// on supporting such changes for the foreseeable future.
 @sealed
-class AliasError extends UnsupportedError {
+class AliasException extends FormatException {
   /// The path that caused the error
   final Iterable<Object?> path;
 
   /// The anchor node of the alias
   final YamlNode anchor;
 
-  AliasError(this.path, this.anchor)
+  AliasException(this.path, this.anchor)
       : super('Encountered an alias node along $path! '
             'Alias nodes are nodes that refer to a previously serialized '
             'nodes, and are denoted by either the "*" or the "&" indicators in '
diff --git a/pkgs/yaml_edit/lib/yaml_edit.dart b/pkgs/yaml_edit/lib/yaml_edit.dart
index c89c3b8..f4d7d75 100644
--- a/pkgs/yaml_edit/lib/yaml_edit.dart
+++ b/pkgs/yaml_edit/lib/yaml_edit.dart
@@ -23,5 +23,6 @@
 library yaml_edit;
 
 export 'src/editor.dart';
+export 'src/errors.dart' show AliasException;
 export 'src/source_edit.dart';
 export 'src/wrap.dart' show wrapAsYamlNode;
diff --git a/pkgs/yaml_edit/pubspec.yaml b/pkgs/yaml_edit/pubspec.yaml
index f4c08df..fd13841 100644
--- a/pkgs/yaml_edit/pubspec.yaml
+++ b/pkgs/yaml_edit/pubspec.yaml
@@ -1,5 +1,5 @@
 name: yaml_edit
-version: 2.1.1
+version: 2.2.0
 description: A library for YAML manipulation with comment and whitespace preservation.
 repository: https://github.com/dart-lang/yaml_edit
 issue_tracker: https://github.com/dart-lang/yaml_edit/issues
diff --git a/pkgs/yaml_edit/test/alias_test.dart b/pkgs/yaml_edit/test/alias_test.dart
index 1663bd8..acc0df7 100644
--- a/pkgs/yaml_edit/test/alias_test.dart
+++ b/pkgs/yaml_edit/test/alias_test.dart
@@ -16,7 +16,7 @@
 - &SS Sammy Sosa
 - *SS
 ''');
-      expect(() => doc.remove([0]), throwsAliasError);
+      expect(() => doc.remove([0]), throwsAliasException);
     });
 
     test('removing an alias reference results in AliasError', () {
@@ -25,7 +25,7 @@
 - *SS
 ''');
 
-      expect(() => doc.remove([1]), throwsAliasError);
+      expect(() => doc.remove([1]), throwsAliasException);
     });
 
     test('it is okay to remove a non-alias node', () {
@@ -50,7 +50,7 @@
 b: *SS
 ''');
 
-      expect(() => doc.remove(['a']), throwsAliasError);
+      expect(() => doc.remove(['a']), throwsAliasException);
     });
 
     test('removing an alias reference value results in AliasError', () {
@@ -59,7 +59,7 @@
 b: *SS
 ''');
 
-      expect(() => doc.remove(['b']), throwsAliasError);
+      expect(() => doc.remove(['b']), throwsAliasException);
     });
 
     test('removing an alias anchor key results in AliasError', () {
@@ -68,7 +68,7 @@
 b: *SS
 ''');
 
-      expect(() => doc.remove(['Sammy Sosa']), throwsAliasError);
+      expect(() => doc.remove(['Sammy Sosa']), throwsAliasException);
     });
 
     test('removing an alias reference key results in AliasError', () {
@@ -77,7 +77,7 @@
 *SS : b
 ''');
 
-      expect(() => doc.remove(['Sammy Sosa']), throwsAliasError);
+      expect(() => doc.remove(['Sammy Sosa']), throwsAliasException);
     });
 
     test('it is okay to remove a non-alias node', () {
@@ -103,7 +103,7 @@
 - *SS
 ''');
 
-      expect(() => doc.remove([0]), throwsAliasError);
+      expect(() => doc.remove([0]), throwsAliasException);
     });
 
     test('nested list alias references are detected too', () {
@@ -113,7 +113,7 @@
   - *SS
 ''');
 
-      expect(() => doc.remove([1]), throwsAliasError);
+      expect(() => doc.remove([1]), throwsAliasException);
     });
 
     test('removing nested map alias anchor results in AliasError', () {
@@ -123,7 +123,7 @@
 b: *SS
 ''');
 
-      expect(() => doc.remove(['a']), throwsAliasError);
+      expect(() => doc.remove(['a']), throwsAliasException);
     });
 
     test('removing nested map alias reference results in AliasError', () {
@@ -133,7 +133,7 @@
   c: *SS
 ''');
 
-      expect(() => doc.remove(['b']), throwsAliasError);
+      expect(() => doc.remove(['b']), throwsAliasException);
     });
   });
 }
diff --git a/pkgs/yaml_edit/test/test_utils.dart b/pkgs/yaml_edit/test/test_utils.dart
index 4924340..8a2be42 100644
--- a/pkgs/yaml_edit/test/test_utils.dart
+++ b/pkgs/yaml_edit/test/test_utils.dart
@@ -32,7 +32,7 @@
 Matcher throwsPathError = throwsA(isA<PathError>());
 
 /// A matcher for functions that throw [AliasError].
-Matcher throwsAliasError = throwsA(isA<AliasError>());
+Matcher throwsAliasException = throwsA(isA<AliasException>());
 
 /// Enum to hold the possible modification methods.
 enum YamlModificationMethod {