Skip to content

Commit 57d6ef4

Browse files
ad mimetype match function helper
1 parent 0d4e23f commit 57d6ef4

File tree

3 files changed

+96
-64
lines changed

3 files changed

+96
-64
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@primoui/utils",
33
"description": "A lightweight set of utilities",
4-
"version": "1.3.1",
4+
"version": "1.3.2",
55
"license": "MIT",
66
"type": "module",
77
"author": {

src/helpers/helpers.test.ts

Lines changed: 63 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
getInitials,
77
getShortcutLabel,
88
isCuid,
9+
isMimeTypeMatch,
910
isTruthy,
1011
joinAsSentence,
1112
nullsToUndefined,
@@ -286,29 +287,6 @@ describe("nullsToUndefined", () => {
286287
})
287288
})
288289

289-
it("should mutate the original object", () => {
290-
const input = {
291-
name: "John",
292-
age: null,
293-
}
294-
295-
const result = nullsToUndefined(input)
296-
297-
// Should return the same reference
298-
expect(result).toBe(input)
299-
// Original object should be mutated
300-
expect(input.age).toEqual(undefined)
301-
})
302-
303-
it("should handle arrays (current behavior: not processed recursively)", () => {
304-
const input = [null, "hello", null, 42]
305-
const result = nullsToUndefined(input)
306-
307-
// Arrays are not plain objects (constructor.name !== "Object"), so they're returned as-is
308-
expect(result).toEqual([null, "hello", null, 42])
309-
expect(result).toBe(input)
310-
})
311-
312290
it("should handle Date objects (current behavior: processed as objects)", () => {
313291
const date = new Date("2023-01-01")
314292
const result = nullsToUndefined(date)
@@ -317,52 +295,74 @@ describe("nullsToUndefined", () => {
317295
expect(result).toEqual(date)
318296
expect(result).toBe(date)
319297
})
298+
})
320299

321-
it("should handle objects containing arrays", () => {
322-
const input = {
323-
list: [null, "item", null],
324-
name: null,
325-
}
300+
describe("isMimeTypeMatch", () => {
301+
it("should match exact MIME types", () => {
302+
expect(isMimeTypeMatch("image/jpeg", ["image/jpeg"])).toBe(true)
303+
expect(isMimeTypeMatch("text/plain", ["text/plain"])).toBe(true)
304+
expect(isMimeTypeMatch("application/json", ["application/json"])).toBe(true)
305+
})
326306

327-
const result = nullsToUndefined(input)
307+
it("should match wildcard patterns", () => {
308+
expect(isMimeTypeMatch("image/jpeg", ["image/*"])).toBe(true)
309+
expect(isMimeTypeMatch("image/png", ["image/*"])).toBe(true)
310+
expect(isMimeTypeMatch("image/gif", ["image/*"])).toBe(true)
311+
expect(isMimeTypeMatch("text/html", ["text/*"])).toBe(true)
312+
expect(isMimeTypeMatch("text/css", ["text/*"])).toBe(true)
313+
expect(isMimeTypeMatch("application/pdf", ["application/*"])).toBe(true)
314+
})
328315

329-
expect(result).toEqual({
330-
list: [null, "item", null], // Array is not processed
331-
name: undefined, // Object property is processed
332-
})
316+
it("should not match different types", () => {
317+
expect(isMimeTypeMatch("image/jpeg", ["text/plain"])).toBe(false)
318+
expect(isMimeTypeMatch("text/plain", ["image/jpeg"])).toBe(false)
319+
expect(isMimeTypeMatch("application/json", ["image/*"])).toBe(false)
320+
expect(isMimeTypeMatch("text/html", ["image/*"])).toBe(false)
333321
})
334322

335-
it("should handle complex mixed data structures", () => {
336-
const input = {
337-
id: 1,
338-
name: null,
339-
metadata: {
340-
created: "2023-01-01",
341-
updated: null,
342-
tags: ["tag1", null, "tag2"],
343-
config: {
344-
enabled: null,
345-
value: 42,
346-
},
347-
},
348-
stats: null,
349-
}
323+
it("should not match different subtypes without wildcard", () => {
324+
expect(isMimeTypeMatch("image/jpeg", ["image/png"])).toBe(false)
325+
expect(isMimeTypeMatch("text/html", ["text/plain"])).toBe(false)
326+
expect(isMimeTypeMatch("application/json", ["application/xml"])).toBe(false)
327+
})
350328

351-
const result = nullsToUndefined(input)
329+
it("should match against multiple patterns", () => {
330+
expect(isMimeTypeMatch("image/jpeg", ["image/*", "text/plain"])).toBe(true)
331+
expect(isMimeTypeMatch("text/plain", ["image/*", "text/plain"])).toBe(true)
332+
expect(isMimeTypeMatch("application/json", ["image/*", "text/plain", "application/json"])).toBe(
333+
true,
334+
)
335+
})
352336

353-
expect(result).toEqual({
354-
id: 1,
355-
name: undefined,
356-
metadata: {
357-
created: "2023-01-01",
358-
updated: undefined,
359-
tags: ["tag1", null, "tag2"], // Arrays not processed
360-
config: {
361-
enabled: undefined,
362-
value: 42,
363-
},
364-
},
365-
stats: undefined,
366-
})
337+
it("should not match if none of the patterns match", () => {
338+
expect(isMimeTypeMatch("video/mp4", ["image/*", "text/plain"])).toBe(false)
339+
expect(isMimeTypeMatch("audio/mpeg", ["image/jpeg", "text/html"])).toBe(false)
340+
})
341+
342+
it("should handle empty patterns array", () => {
343+
expect(isMimeTypeMatch("image/jpeg", [])).toBe(false)
344+
expect(isMimeTypeMatch("text/plain", [])).toBe(false)
345+
})
346+
347+
it("should handle edge cases with MIME type format", () => {
348+
expect(isMimeTypeMatch("image/jpeg", ["image/jpeg"])).toBe(true)
349+
expect(isMimeTypeMatch("application/vnd.api+json", ["application/*"])).toBe(true)
350+
expect(isMimeTypeMatch("application/vnd.api+json", ["application/vnd.api+json"])).toBe(true)
351+
})
352+
353+
it("should be case sensitive", () => {
354+
expect(isMimeTypeMatch("Image/JPEG", ["image/jpeg"])).toBe(false)
355+
expect(isMimeTypeMatch("image/jpeg", ["Image/JPEG"])).toBe(false)
356+
expect(isMimeTypeMatch("IMAGE/JPEG", ["image/*"])).toBe(false)
357+
})
358+
359+
it("should handle complex MIME types", () => {
360+
expect(
361+
isMimeTypeMatch("application/vnd.openxmlformats-officedocument.wordprocessingml.document", [
362+
"application/*",
363+
]),
364+
).toBe(true)
365+
expect(isMimeTypeMatch("application/vnd.ms-excel", ["application/vnd.ms-excel"])).toBe(true)
366+
expect(isMimeTypeMatch("text/html; charset=utf-8", ["text/*"])).toBe(true)
367367
})
368368
})

src/helpers/helpers.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,35 @@ export const nullsToUndefined = <T>(obj: T): ReplaceNullWithUndefined<T> => {
253253

254254
return obj as any
255255
}
256+
257+
/**
258+
* Checks if a MIME type matches any of the provided patterns.
259+
* Supports wildcard matching for subtypes (e.g., "image/*").
260+
*
261+
* @param mimeType - The MIME type to check (e.g., "image/jpeg", "text/plain")
262+
* @param patterns - Array of MIME type patterns to match against (e.g., ["image/*", "text/plain"])
263+
* @returns True if the MIME type matches any of the patterns, false otherwise
264+
*
265+
* @example
266+
* ```typescript
267+
* isMimeTypeMatch("image/jpeg", ["image/*"]) // returns true
268+
* isMimeTypeMatch("text/plain", ["image/*", "text/plain"]) // returns true
269+
* isMimeTypeMatch("application/json", ["image/*"]) // returns false
270+
* ```
271+
*/
272+
export const isMimeTypeMatch = (mimeType: string, patterns: string[]) => {
273+
return patterns.some(pattern => {
274+
// Split type/subtype for both mimeType and pattern
275+
const [type, subtype] = mimeType.split("/")
276+
const [pType, pSubtype] = pattern.split("/")
277+
278+
// Type must match
279+
if (type !== pType) return false
280+
281+
// Wildcard matches any subtype
282+
if (pSubtype === "*") return true
283+
284+
// Exact subtype match
285+
return subtype === pSubtype
286+
})
287+
}

0 commit comments

Comments
 (0)