Handle author and authors in a more sane way

There is at least one published package with both author & authors set
https://pub.dartlang.org/packages/crclib/versions/1.0.0

So we do normalization if both are set, eliminating duplicates and
providing reasonable values from both author and authors properties

Fixes https://github.com/dart-lang/pubspec_parse/issues/2
diff --git a/pkgs/pubspec_parse/lib/src/pubspec.dart b/pkgs/pubspec_parse/lib/src/pubspec.dart
index 6a5c3a6..90efa1c 100644
--- a/pkgs/pubspec_parse/lib/src/pubspec.dart
+++ b/pkgs/pubspec_parse/lib/src/pubspec.dart
@@ -16,21 +16,24 @@
   final String homepage;
   final String documentation;
   final String description;
-  final String author;
+
+  /// If there is exactly 1 value in [authors], returns it.
+  ///
+  /// If there are 0 or more than 1, returns `null`.
+  @Deprecated(
+      'Here for completeness, but not recommended. Use `authors` instead.')
+  String get author {
+    if (authors.length == 1) {
+      return authors.single;
+    }
+    return null;
+  }
+
   final List<String> authors;
 
   @JsonKey(fromJson: _environmentMap)
   final Map<String, VersionConstraint> environment;
 
-  List<String> get allAuthors {
-    var values = <String>[];
-    if (author != null) {
-      values.add(author);
-    }
-    values.addAll(authors);
-    return values;
-  }
-
   @JsonKey(fromJson: _versionFromString)
   final Version version;
 
@@ -43,19 +46,21 @@
   @JsonKey(name: 'dependency_overrides', fromJson: _getDeps, nullable: false)
   final Map<String, Dependency> dependencyOverrides;
 
+  /// If [author] and [authors] are both provided, their values are combined
+  /// with duplicates eliminated.
   Pubspec(
     this.name, {
     this.version,
-    this.author,
-    this.environment,
+    String author,
     List<String> authors,
+    this.environment,
     this.homepage,
     this.documentation,
     this.description,
     Map<String, Dependency> dependencies,
     Map<String, Dependency> devDependencies,
     Map<String, Dependency> dependencyOverrides,
-  })  : this.authors = authors ?? const [],
+  })  : this.authors = _normalizeAuthors(author, authors),
         this.dependencies = dependencies ?? const {},
         this.devDependencies = devDependencies ?? const {},
         this.dependencyOverrides = dependencyOverrides ?? const {} {
@@ -65,6 +70,17 @@
   }
 
   factory Pubspec.fromJson(Map json) => _$PubspecFromJson(json);
+
+  static List<String> _normalizeAuthors(String author, List<String> authors) {
+    var value = new Set<String>();
+    if (author != null) {
+      value.add(author);
+    }
+    if (authors != null) {
+      value.addAll(authors);
+    }
+    return value.toList();
+  }
 }
 
 // TODO: maybe move this to `dependencies.dart`?
diff --git a/pkgs/pubspec_parse/lib/src/pubspec.g.dart b/pkgs/pubspec_parse/lib/src/pubspec.g.dart
index b98d766..4f040ff 100644
--- a/pkgs/pubspec_parse/lib/src/pubspec.g.dart
+++ b/pkgs/pubspec_parse/lib/src/pubspec.g.dart
@@ -17,10 +17,10 @@
             version: $checkedConvert(json, 'version',
                 (v) => v == null ? null : _versionFromString(v as String)),
             author: $checkedConvert(json, 'author', (v) => v as String),
-            environment: $checkedConvert(json, 'environment',
-                (v) => v == null ? null : _environmentMap(v as Map)),
             authors: $checkedConvert(json, 'authors',
                 (v) => (v as List)?.map((e) => e as String)?.toList()),
+            environment: $checkedConvert(json, 'environment',
+                (v) => v == null ? null : _environmentMap(v as Map)),
             homepage: $checkedConvert(json, 'homepage', (v) => v as String),
             documentation:
                 $checkedConvert(json, 'documentation', (v) => v as String),
diff --git a/pkgs/pubspec_parse/test/parse_test.dart b/pkgs/pubspec_parse/test/parse_test.dart
index 7a4af76..bfe20f0 100644
--- a/pkgs/pubspec_parse/test/parse_test.dart
+++ b/pkgs/pubspec_parse/test/parse_test.dart
@@ -10,38 +10,61 @@
   test('trival', () {
     var value = parse({'name': 'sample'});
     expect(value.name, 'sample');
+    // ignore: deprecated_member_use
+    expect(value.author, isNull);
     expect(value.authors, isEmpty);
     expect(value.dependencies, isEmpty);
   });
 
-  test('one author', () {
-    var value = parse({'name': 'sample', 'author': 'name@example.com'});
-    expect(value.allAuthors, ['name@example.com']);
-  });
-
-  test('one author, via authors', () {
-    var value = parse({
-      'name': 'sample',
-      'authors': ['name@example.com']
+  group('author, authors', () {
+    test('one author', () {
+      var value = parse({'name': 'sample', 'author': 'name@example.com'});
+      // ignore: deprecated_member_use
+      expect(value.author, 'name@example.com');
+      expect(value.authors, ['name@example.com']);
     });
-    expect(value.authors, ['name@example.com']);
-  });
 
-  test('many authors', () {
-    var value = parse({
-      'name': 'sample',
-      'authors': ['name@example.com', 'name2@example.com']
+    test('one author, via authors', () {
+      var value = parse({
+        'name': 'sample',
+        'authors': ['name@example.com']
+      });
+      // ignore: deprecated_member_use
+      expect(value.author, 'name@example.com');
+      expect(value.authors, ['name@example.com']);
     });
-    expect(value.authors, ['name@example.com', 'name2@example.com']);
-  });
 
-  test('author and authors', () {
-    var value = parse({
-      'name': 'sample',
-      'author': 'name@example.com',
-      'authors': ['name2@example.com']
+    test('many authors', () {
+      var value = parse({
+        'name': 'sample',
+        'authors': ['name@example.com', 'name2@example.com']
+      });
+      // ignore: deprecated_member_use
+      expect(value.author, isNull);
+      expect(value.authors, ['name@example.com', 'name2@example.com']);
     });
-    expect(value.allAuthors, ['name@example.com', 'name2@example.com']);
+
+    test('author and authors', () {
+      var value = parse({
+        'name': 'sample',
+        'author': 'name@example.com',
+        'authors': ['name2@example.com']
+      });
+      // ignore: deprecated_member_use
+      expect(value.author, isNull);
+      expect(value.authors, ['name@example.com', 'name2@example.com']);
+    });
+
+    test('duplicate author values', () {
+      var value = parse({
+        'name': 'sample',
+        'author': 'name@example.com',
+        'authors': ['name@example.com', 'name@example.com']
+      });
+      // ignore: deprecated_member_use
+      expect(value.author, 'name@example.com');
+      expect(value.authors, ['name@example.com']);
+    });
   });
 
   group('invalid', () {