Merge pull request #33 from kenzieschmoll/extensionFromMime

Add `extensionFromMime` utility.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ac29147..a0ca552 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 0.9.7
+* Add `extensionFromMime` utility function.
+
 # 0.9.6+3
 
 * Change the mime type for Dart source from `application/dart` to `text/x-dart`.
diff --git a/lib/src/default_extension_map.dart b/lib/src/default_extension_map.dart
index c7add48..d951b23 100644
--- a/lib/src/default_extension_map.dart
+++ b/lib/src/default_extension_map.dart
@@ -4,8 +4,7 @@
 
 library mime.extension_map;
 
-// TODO(ajohnsen): Use const map once Issue 7559 is fixed.
-final Map<String, String> defaultExtensionMap = <String, String>{
+const Map<String, String> defaultExtensionMap = <String, String>{
   '123': 'application/vnd.lotus-1-2-3',
   '3dml': 'text/vnd.in3d.3dml',
   '3ds': 'image/x-3ds',
diff --git a/lib/src/mime_type.dart b/lib/src/mime_type.dart
index 84ac306..3b220e7 100644
--- a/lib/src/mime_type.dart
+++ b/lib/src/mime_type.dart
@@ -25,6 +25,20 @@
 String lookupMimeType(String path, {List<int> headerBytes}) =>
     _globalResolver.lookup(path, headerBytes: headerBytes);
 
+/// Returns the extension for the given MIME type.
+///
+/// If there are multiple extensions for [mime], return the first occurrence in
+/// the map. If there are no extensions for [mime], return [mime].
+String extensionFromMime(String mime) {
+  mime = mime.toLowerCase();
+  for (final entry in defaultExtensionMap.entries) {
+    if (defaultExtensionMap[entry.key] == mime) {
+      return entry.key;
+    }
+  }
+  return mime;
+}
+
 /// MIME-type resolver class, used to customize the lookup of mime-types.
 class MimeTypeResolver {
   final Map<String, String> _extensionMap = {};
diff --git a/pubspec.yaml b/pubspec.yaml
index b0c21b3..16c6876 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: mime
-version: 0.9.7-dev
+version: 0.9.7
 
 description: >-
   Utilities for handling media (MIME) types, including determining a type from
diff --git a/test/default_extension_map_test.dart b/test/default_extension_map_test.dart
new file mode 100644
index 0000000..b5539dd
--- /dev/null
+++ b/test/default_extension_map_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:mime/src/default_extension_map.dart';
+import 'package:test/test.dart';
+
+void main() {
+  group('defaultExtensionMap', () {
+    test('keys are lowercase', () {
+      for (final key in defaultExtensionMap.keys) {
+        expect(key, equals(key.toLowerCase()));
+      }
+    });
+  });
+}
diff --git a/test/mime_type_test.dart b/test/mime_type_test.dart
index 9d02772..7f9169c 100644
--- a/test/mime_type_test.dart
+++ b/test/mime_type_test.dart
@@ -123,4 +123,22 @@
 
     expect(defaultMagicNumbersMaxLength, actualMaxBytes);
   });
+
+  group('extensionFromMime', () {
+    test('returns match for mime with single extension', () {
+      expect(extensionFromMime('application/json'), equals('json'));
+      expect(extensionFromMime('application/java-archive'), equals('jar'));
+    });
+
+    test('returns first match for mime with multiple extensions', () {
+      expect(extensionFromMime('text/html'), equals('htm'));
+      expect(extensionFromMime('application/x-cbr'), equals('cb7'));
+    });
+
+    test('returns inputted string for unrecognized mime', () {
+      expect(
+          extensionFromMime('unrecognized_mime'), equals('unrecognized_mime'));
+      expect(extensionFromMime('i/am/not/a/mime'), equals('i/am/not/a/mime'));
+    });
+  });
 }