From be50f1f076d2fc55898dd5ed82a863d549c433af Mon Sep 17 00:00:00 2001 From: Anthony GAEREMYNCK <1@anthony.sh> Date: Fri, 31 Jul 2026 12:57:35 +0200 Subject: [PATCH] feat: add font MIME types and fix dfont/ico detection collision Co-Authored-By: Claude Sonnet 5 --- src/mime.js | 12 ++++++++++++ test/mime.test.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/mime.js b/src/mime.js index 37f3578..ed99c7d 100644 --- a/src/mime.js +++ b/src/mime.js @@ -1,4 +1,6 @@ import { fileTypeFromFile } from 'file-type'; +import fs from 'node:fs/promises'; +import { probeDfont } from './converters/dfont.js'; const OUTPUT_MIME_TYPES = { jpg: 'image/jpeg', @@ -17,6 +19,9 @@ const OUTPUT_MIME_TYPES = { md: 'text/markdown', csv: 'text/csv', xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + ttf: 'font/ttf', + otf: 'font/otf', + woff: 'font/woff', }; export async function detectInputMime(filePath) { @@ -46,6 +51,13 @@ function normalizeFormat(format) { } export async function resolveInputFormat(filePath, declaredFormat) { + if (declaredFormat === 'dfont') { + const buffer = await fs.readFile(filePath); + return probeDfont(buffer) + ? { mime: 'application/x-dfont', valid: true } + : { mime: null, valid: false }; + } + const detected = await detectInputMime(filePath); if (!detected) { diff --git a/test/mime.test.js b/test/mime.test.js index 1780bce..f46c121 100644 --- a/test/mime.test.js +++ b/test/mime.test.js @@ -104,3 +104,35 @@ describe('resolveInputFormat — heic/heif alias', () => { expect(result.valid).toBe(true); }); }); + +describe('outputMimeType — fonts', () => { + it('returns the correct MIME type for each font target format', () => { + expect(outputMimeType('ttf')).toBe('font/ttf'); + expect(outputMimeType('otf')).toBe('font/otf'); + expect(outputMimeType('woff')).toBe('font/woff'); + }); +}); + +describe('resolveInputFormat — dfont', () => { + it('confirms file-type alone misidentifies the dfont fixture as ico (documents the bug this fix works around)', async () => { + const fixturePath = path.join(import.meta.dirname, 'fixtures', 'sample.dfont'); + const detected = await detectInputMime(fixturePath); + expect(detected.ext).toBe('ico'); + }); + + it('accepts a real dfont file despite that misidentification', async () => { + const fixturePath = path.join(import.meta.dirname, 'fixtures', 'sample.dfont'); + const result = await resolveInputFormat(fixturePath, 'dfont'); + expect(result).toEqual({ mime: 'application/x-dfont', valid: true }); + }); + + it('rejects content starting with the colliding magic bytes that is not a real dfont', async () => { + const fixturePath = path.join(import.meta.dirname, 'fixtures', 'sample-fake.dfont'); + await fs.writeFile(fixturePath, Buffer.from([0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10])); + + const result = await resolveInputFormat(fixturePath, 'dfont'); + expect(result).toEqual({ mime: null, valid: false }); + + await fs.unlink(fixturePath); + }); +});