Skip to content

Commit c6f32da

Browse files
Copilotneotrow
andcommitted
Add comprehensive MimeType utility functions
Co-authored-by: neotrow <92933708+neotrow@users.noreply.github.com>
1 parent b1a88f7 commit c6f32da

3 files changed

Lines changed: 208 additions & 0 deletions

File tree

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

0 commit comments

Comments
 (0)