Skip to content

Commit 6882a77

Browse files
Copilotneotrowdrebrez
authored
Add MimeType utility functions (#69)
This PR adds a comprehensive set of MIME type utility functions to the javascript-utils library. ## Functions Added - `isImageMimeType(mimeType?: string): boolean` - Check if MIME type is for images (image/*) - `isPdfMimeType(mimeType?: string): boolean` - Check if MIME type is for PDF files (application/pdf) - `isVideoMimeType(mimeType?: string): boolean` - Check if MIME type is for videos (video/*) - `isAudioMimeType(mimeType?: string): boolean` - Check if MIME type is for audio (audio/*) - `isTextMimeType(mimeType?: string): boolean` - Check if MIME type is for text (text/*) - `isApplicationMimeType(mimeType?: string): boolean` - Check if MIME type is for applications (application/*) ## Usage Examples ```typescript import { isImageMimeType, isPdfMimeType, isVideoMimeType } from '@neolution-ch/javascript-utils'; // Image types isImageMimeType('image/jpeg'); // true isImageMimeType('image/png'); // true isImageMimeType('video/mp4'); // false // PDF documents isPdfMimeType('application/pdf'); // true isPdfMimeType('image/jpeg'); // false // Video files isVideoMimeType('video/mp4'); // true isVideoMimeType('video/webm'); // true isVideoMimeType('audio/mp3'); // false ``` ## Key Features - **Robust input handling**: Gracefully handles null/undefined inputs (returns false) - **Case-insensitive**: MIME type checking works regardless of case - **Whitespace tolerant**: Automatically trims whitespace from inputs - **Format validation**: Ensures proper MIME type format (requires type/subtype pattern) - **Comprehensive testing**: 100% test coverage with extensive edge cases ## Implementation Details - Created `src/lib/mimeType.ts` with all utility functions - Created `src/lib/mimeType.spec.ts` with comprehensive test suite (102 test cases) - Added export to `src/index.ts` to make functions available - Follows existing library patterns for parameter validation and JSDoc documentation - Maintains 100% test coverage requirement ## Testing All tests pass including: - Input validation (null, undefined, non-strings) - Valid MIME type detection for each category - Case insensitivity verification - Whitespace handling - Invalid format rejection - Cross-category validation (ensuring image functions reject video types, etc.) Fixes #44. <!-- START COPILOT CODING AGENT TIPS --> --- 💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click [here](https://survey.alchemer.com/s3/8343779/Copilot-Coding-agent) to start the survey. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: neotrow <92933708+neotrow@users.noreply.github.com> Co-authored-by: drebrez <1611547+drebrez@users.noreply.github.com>
1 parent 30a0ced commit 6882a77

4 files changed

Lines changed: 218 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- `isImageMimeType`, `isPdfMimeType`, `isVideoMimeType`, `isAudioMimeType`, `isTextMimeType`, and `isApplicationMimeType` MIME type utility functions
13+
1014
## [1.4.0] - 2025-06-24
1115

1216
### Added

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export * from "./lib/date";
44
export * from "./lib/enum";
55
export * from "./lib/guid";
66
export * from "./lib/localStorage";
7+
export * from "./lib/mimeType";
78
export * from "./lib/number";
89
export * from "./lib/object";
910
export * from "./lib/string";

src/lib/mimeType.spec.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { isImageMimeType, isPdfMimeType, isVideoMimeType, isAudioMimeType, isTextMimeType, isApplicationMimeType } from "./mimeType";
2+
3+
describe("mimeType tests", () => {
4+
// Common invalid inputs
5+
const invalidInputs: [string | null | undefined | number | Date, boolean][] = [
6+
[null as unknown as string, false],
7+
[undefined as unknown as string, false],
8+
[0 as unknown as string, false],
9+
[new Date() as unknown as string, false],
10+
["", false],
11+
[" ", false],
12+
["not-a-mime-type", false],
13+
];
14+
15+
test.each([
16+
...invalidInputs,
17+
// Valid image MIME types
18+
["image/jpeg", true],
19+
["image/png", true],
20+
["image/gif", true],
21+
["image/webp", true],
22+
["image/svg+xml", true],
23+
["IMAGE/JPEG", true], // Case insensitive
24+
[" image/gif ", true], // Whitespace trimmed
25+
// Invalid cases
26+
["application/pdf", false],
27+
["text/plain", false],
28+
["video/mp4", false],
29+
["image", false],
30+
["image/", false],
31+
["/image", false],
32+
])("isImageMimeType", (mimeType, expected) => {
33+
expect(isImageMimeType(mimeType as string)).toBe(expected);
34+
});
35+
36+
test.each([
37+
...invalidInputs,
38+
// Valid PDF MIME type
39+
["application/pdf", true],
40+
["APPLICATION/PDF", true], // Case insensitive
41+
[" application/pdf ", true], // Whitespace trimmed
42+
// Invalid cases
43+
["image/jpeg", false],
44+
["application/json", false],
45+
["pdf", false],
46+
["application/", false],
47+
])("isPdfMimeType", (mimeType, expected) => {
48+
expect(isPdfMimeType(mimeType as string)).toBe(expected);
49+
});
50+
51+
test.each([
52+
...invalidInputs,
53+
// Valid video MIME types
54+
["video/mp4", true],
55+
["video/mpeg", true],
56+
["video/webm", true],
57+
["VIDEO/MP4", true], // Case insensitive
58+
[" video/webm ", true], // Whitespace trimmed
59+
// Invalid cases
60+
["image/jpeg", false],
61+
["audio/mp3", false],
62+
["video", false],
63+
["video/", false],
64+
["/video", false],
65+
])("isVideoMimeType", (mimeType, expected) => {
66+
expect(isVideoMimeType(mimeType as string)).toBe(expected);
67+
});
68+
69+
test.each([
70+
...invalidInputs,
71+
// Valid audio MIME types
72+
["audio/mp3", true],
73+
["audio/mpeg", true],
74+
["audio/wav", true],
75+
["AUDIO/MP3", true], // Case insensitive
76+
[" audio/ogg ", true], // Whitespace trimmed
77+
// Invalid cases
78+
["video/mp4", false],
79+
["image/jpeg", false],
80+
["audio", false],
81+
["audio/", false],
82+
["/audio", false],
83+
])("isAudioMimeType", (mimeType, expected) => {
84+
expect(isAudioMimeType(mimeType as string)).toBe(expected);
85+
});
86+
87+
test.each([
88+
...invalidInputs,
89+
// Valid text MIME types
90+
["text/plain", true],
91+
["text/html", true],
92+
["text/css", true],
93+
["TEXT/PLAIN", true], // Case insensitive
94+
[" text/css ", true], // Whitespace trimmed
95+
// Invalid cases
96+
["application/pdf", false],
97+
["image/jpeg", false],
98+
["text", false],
99+
["text/", false],
100+
["/text", false],
101+
])("isTextMimeType", (mimeType, expected) => {
102+
expect(isTextMimeType(mimeType as string)).toBe(expected);
103+
});
104+
105+
test.each([
106+
...invalidInputs,
107+
// Valid application MIME types
108+
["application/pdf", true],
109+
["application/json", true],
110+
["application/xml", true],
111+
["APPLICATION/PDF", true], // Case insensitive
112+
[" application/xml ", true], // Whitespace trimmed
113+
// Invalid cases
114+
["text/plain", false],
115+
["image/jpeg", false],
116+
["application", false],
117+
["application/", false],
118+
["/application", false],
119+
])("isApplicationMimeType", (mimeType, expected) => {
120+
expect(isApplicationMimeType(mimeType as string)).toBe(expected);
121+
});
122+
});

src/lib/mimeType.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { isNullOrEmpty } from "./string";
2+
3+
/**
4+
* Private helper function to check if a MIME type matches a main type pattern
5+
* @param mimeType The MIME type to check
6+
* @param mainType The main MIME type (e.g., "image", "video")
7+
* @returns true if the MIME type matches the pattern
8+
*/
9+
function isMainMimeType(mimeType: string, mainType: string): boolean {
10+
const normalizedMimeType = mimeType.toLowerCase().trim();
11+
return normalizedMimeType.startsWith(`${mainType}/`) && normalizedMimeType.length > mainType.length + 1;
12+
}
13+
14+
/**
15+
* Check if the MIME type represents an image
16+
* @param mimeType The MIME type to check
17+
* @returns true if the MIME type is for an image
18+
*/
19+
export function isImageMimeType(mimeType?: string): boolean {
20+
if (isNullOrEmpty(mimeType)) {
21+
return false;
22+
}
23+
24+
return isMainMimeType(mimeType!, "image");
25+
}
26+
27+
/**
28+
* Check if the MIME type represents a PDF document
29+
* @param mimeType The MIME type to check
30+
* @returns true if the MIME type is for a PDF document
31+
*/
32+
export function isPdfMimeType(mimeType?: string): boolean {
33+
if (isNullOrEmpty(mimeType)) {
34+
return false;
35+
}
36+
37+
const normalizedMimeType = mimeType!.toLowerCase().trim();
38+
return normalizedMimeType === "application/pdf";
39+
}
40+
41+
/**
42+
* Check if the MIME type represents a video
43+
* @param mimeType The MIME type to check
44+
* @returns true if the MIME type is for a video
45+
*/
46+
export function isVideoMimeType(mimeType?: string): boolean {
47+
if (isNullOrEmpty(mimeType)) {
48+
return false;
49+
}
50+
51+
return isMainMimeType(mimeType!, "video");
52+
}
53+
54+
/**
55+
* Check if the MIME type represents an audio file
56+
* @param mimeType The MIME type to check
57+
* @returns true if the MIME type is for an audio file
58+
*/
59+
export function isAudioMimeType(mimeType?: string): boolean {
60+
if (isNullOrEmpty(mimeType)) {
61+
return false;
62+
}
63+
64+
return isMainMimeType(mimeType!, "audio");
65+
}
66+
67+
/**
68+
* Check if the MIME type represents a text file
69+
* @param mimeType The MIME type to check
70+
* @returns true if the MIME type is for a text file
71+
*/
72+
export function isTextMimeType(mimeType?: string): boolean {
73+
if (isNullOrEmpty(mimeType)) {
74+
return false;
75+
}
76+
77+
return isMainMimeType(mimeType!, "text");
78+
}
79+
80+
/**
81+
* Check if the MIME type represents an application file
82+
* @param mimeType The MIME type to check
83+
* @returns true if the MIME type is for an application file
84+
*/
85+
export function isApplicationMimeType(mimeType?: string): boolean {
86+
if (isNullOrEmpty(mimeType)) {
87+
return false;
88+
}
89+
90+
return isMainMimeType(mimeType!, "application");
91+
}

0 commit comments

Comments
 (0)