Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pkg-mime] contenttype to ext #431

Merged
merged 38 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
9355522
initial code from pr !15
mx1up Jan 5, 2023
e7f328e
update copyright year
mx1up Jan 5, 2023
7eb72c3
improve lookup: case-insensitive and use firstWhereOrNull instead of …
mx1up Jan 6, 2023
80079be
tests cleanup
mx1up Jan 6, 2023
d3ce7ae
check baseline
mx1up Jan 6, 2023
29050ff
test to check whether each mimetype with multiple extensions has a pr…
mx1up Jan 6, 2023
84f3bd8
reformat
mx1up Jan 6, 2023
c27fa37
apparently, the function already existed :roll-eyes: but the preferre…
mx1up Jan 6, 2023
f2a62f7
probably better not to enforce a preferred extension for mime types w…
mx1up Jan 6, 2023
bdb76d3
added some preferred extensions for common file formats
mx1up Jan 6, 2023
16f54d5
cleanup old tests
mx1up Jan 6, 2023
dccafc0
test orElse param for unknown mime type
mx1up Jan 16, 2023
59c6ec2
link to file
mx1up Jan 16, 2023
9e4b9d0
fix title to be more accurate
mx1up Jan 16, 2023
bc90ebd
rename to existing function
mx1up Jan 16, 2023
cd5e501
add standard behavior to make example more clear
mx1up Jan 16, 2023
557520e
include text/plain mapping again
mx1up Jan 16, 2023
8c1f0a0
remove collection dependency
mx1up Jan 17, 2023
0701165
lookupExtension has been renamed to existing extensionFromMime
mx1up Jan 27, 2023
7ad3723
drop non-nullable extensionFromMime variant per review suggestion
mx1up Dec 13, 2023
58ad484
doc update: try using noun phrase; don't refer to implementation details
mx1up Dec 13, 2023
eed2ba9
don't use extension method
mx1up Dec 13, 2023
dc5db0b
remove addMimeType and leave it for another time..
mx1up Dec 13, 2023
d285aae
remove addMimeType documentation
mx1up Dec 13, 2023
342b63f
be more specific about extension
mx1up Feb 19, 2024
40cd80c
review feedback: avoid abbreviations, just overwrite function param
mx1up Feb 19, 2024
60730a6
since extensions can no longer by added at runtime, we can optimize a…
mx1up Feb 19, 2024
04f8169
local var no longer needed
mx1up Feb 19, 2024
8ba5efb
update docs
mx1up Feb 19, 2024
c1d7b69
update docs
mx1up Feb 19, 2024
e654a32
documentation updates
mx1up Aug 27, 2024
c236bd8
remove unnecessary addAll
mx1up Aug 27, 2024
b11854c
remove unnecessary group
mx1up Aug 27, 2024
874f740
bump version + add changelog
mx1up Aug 27, 2024
d5e3d47
remove superfluous line
mx1up Aug 28, 2024
7b3193f
breaking release because of removed method
mx1up Aug 29, 2024
c33a7ea
add some more default extensions
mx1up Aug 29, 2024
b5e6981
document breaking change correctly
mx1up Aug 30, 2024
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
4 changes: 4 additions & 0 deletions pkgs/mime/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ All files in the project must start with the following header.
Contributions made by corporations are covered by a different agreement than the
one above, the
[Software Grant and Corporate Contributor License Agreement](https://developers.google.com/open-source/cla/corporate).

### Adding an extension / MIME type mapping
If a MIME type ends up with multiple extensions, it is recommended to define a
preferred extension in `_defaultMimeTypeMap` in [extension.dart](lib/src/extension.dart).
11 changes: 11 additions & 0 deletions pkgs/mime/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,14 @@ request
.map((part) => part.fold(0, (p, d) => p + d))
.listen((length) => print('Part with length $length'));
```

## Determining file extension by MIME type

The top level function `extensionFromMime` can be used to determine the
file extension of a given MIME type.

```dart
print(extensionFromMime('text/html')); // Will print html
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conside formatting the comment as:

..)); // Prints "html".

(Dittos below.)

Be direct in comments. It saves words and usually avoids ambiguity. Present tense verbs win!
Distinguish different kinds of text. Here "html" is an actual string value, but is not distinguished from the other words.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

print(extensionFromMime('image/jpeg')); // Will print jpg
print(extensionFromMime('application/pdf')); // Will print pdf
```
1 change: 1 addition & 0 deletions pkgs/mime/lib/mime.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/// [Internet media type](http://en.wikipedia.org/wiki/Internet_media_type).
library;

export 'src/extension.dart';
export 'src/mime_multipart_transformer.dart';
export 'src/mime_shared.dart';
export 'src/mime_type.dart';
36 changes: 36 additions & 0 deletions pkgs/mime/lib/src/extension.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) 2023, 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 'default_extension_map.dart';

/// Reverse map of [defaultExtensionMap] with overrides for common extensions
/// since different extensions may map to the same MIME type.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DartDoc should (is recommended to) have a single line first paragraph.

Consider:

/// Default extension for recognized MIME types.
///
/// Is the inverse of [defaultExtensionMap], and where that
/// map has multiple extensions which map to the same 
/// MIME type, this map maps that MIME type to a *default*
/// extension.
/// 
/// Used by [extensionFromMime].

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

final Map<String, String> _defaultMimeTypeMap = {
for (var entry in defaultExtensionMap.entries) entry.value: entry.key,
}..addAll({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put the entries into the same literal. (Just change }..addAll({ to ,, and remove the trailing ).)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

'application/vnd.ms-excel': 'xls',
'application/vnd.ms-powerpoint': 'ppt',
'image/jpeg': 'jpg',
'image/tiff': 'tif',
'image/svg+xml': 'svg',
'text/calendar': 'ics',
'text/javascript': 'js',
'text/plain': 'txt',
'text/sgml': 'sgml',
'text/x-pascal': 'pas',
'video/mp4': 'mp4',
'video/mpeg': 'mpg',
'video/quicktime': 'mov',
'video/x-matroska': 'mkv',
});

/// The file extension for a given MIME type.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe:
/// The default file extension for ...

That hightlights that there can be more, but one is chosen as the default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

///
/// If there are multiple extensions for [mimeType], return preferred extension
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider.

/// If [mimeType] has multiple associated extensions, 
/// the returned string is one of those, chosen as the default
/// extension for that MIME type.
///
/// Returns `null` if [mimeType] is not a recognized and
/// supported MIME type

(Don't link to private members in public API docs. That's an implementation detail.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/// if defined in [_defaultMimeTypeMap], otherwise an extension chosen by the
/// library.
///
/// If no extension is found, `null` is returned.
String? extensionFromMime(String mimeType) =>
_defaultMimeTypeMap[mimeType.toLowerCase()];
14 changes: 0 additions & 14 deletions pkgs/mime/lib/src/mime_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,6 @@ int get defaultMagicNumbersMaxLength => _globalResolver.magicNumbersMaxLength;
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 = {};
Expand Down
35 changes: 35 additions & 0 deletions pkgs/mime/test/extension_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2023, 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/mime.dart';
import 'package:test/test.dart';

void main() {
group('global-lookup-mime-type', () {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for a group that contains every test in the file. Just have the tests directly in main.
(I can see it's copied from somewhere else, where it was not the only group. Here it is.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

test('valid-mime-type', () {
expect(extensionFromMime('text/x-dart'), equals('dart'));
expect(extensionFromMime('text/javascript'), equals('js'));
expect(extensionFromMime('application/java-archive'), equals('jar'));
expect(extensionFromMime('application/json'), equals('json'));
expect(extensionFromMime('application/pdf'), equals('pdf'));
expect(extensionFromMime('application/vnd.ms-excel'), equals('xls'));
expect(extensionFromMime('application/xhtml+xml'), equals('xht'));
expect(extensionFromMime('image/jpeg'), equals('jpg'));
expect(extensionFromMime('image/png'), equals('png'));
expect(extensionFromMime('text/css'), equals('css'));
expect(extensionFromMime('text/html'), equals('htm'));
expect(extensionFromMime('text/plain'), equals('txt'));
expect(extensionFromMime('text/x-c'), equals('c'));
});

test('invalid-mime-type', () {
expect(extensionFromMime('invalid-mime-type'), isNull);
expect(extensionFromMime('invalid/mime/type'), isNull);
});

test('unknown-mime-type', () {
expect(extensionFromMime('application/to-be-invented'), isNull);
});
});
}
17 changes: 0 additions & 17 deletions pkgs/mime/test/mime_type_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -318,21 +318,4 @@ void main() {
expect(initialMagicNumbersMaxLength, 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'));
});
});
}
Loading