Files
yaak/src-web/lib/contentType.ts
Gregory Schier b4a1c418bb Run oxfmt across repo, add format script and docs
Add .oxfmtignore to skip generated bindings and wasm-pack output.
Add npm format script, update DEVELOPMENT.md for Vite+ toolchain,
and format all non-generated files with oxfmt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:15:49 -07:00

100 lines
2.5 KiB
TypeScript

import MimeType from "whatwg-mimetype";
import type { EditorProps } from "../components/core/Editor/Editor";
export function languageFromContentType(
contentType: string | null,
content: string | null = null,
): EditorProps["language"] {
const justContentType = contentType?.split(";")[0] ?? contentType ?? "";
if (justContentType.includes("json")) {
return "json";
}
if (justContentType.includes("xml")) {
return "xml";
}
if (justContentType.includes("html")) {
const detected = languageFromContent(content);
if (detected === "xml") {
// If it's detected as XML, but is already HTML, don't change it
return "html";
}
return detected;
}
if (justContentType.includes("javascript")) {
// Sometimes `application/javascript` returns JSON, so try detecting that
return languageFromContent(content, "javascript");
}
if (justContentType.includes("markdown")) {
return "markdown";
}
return languageFromContent(content, "text");
}
export function languageFromContent(
content: string | null,
fallback?: EditorProps["language"],
): EditorProps["language"] {
if (content == null) return "text";
const firstBytes = content.slice(0, 20).trim();
if (firstBytes.startsWith("{") || firstBytes.startsWith("[")) {
return "json";
}
if (
firstBytes.toLowerCase().startsWith("<!doctype") ||
firstBytes.toLowerCase().startsWith("<html")
) {
return "html";
}
if (firstBytes.startsWith("<")) {
return "xml";
}
return fallback;
}
export function isJSON(content: string | null | undefined): boolean {
if (typeof content !== "string") return false;
try {
JSON.parse(content);
return true;
} catch {
return false;
}
}
export function isProbablyTextContentType(contentType: string | null): boolean {
if (contentType == null) return false;
const mimeType = getMimeTypeFromContentType(contentType).essence;
const normalized = mimeType.toLowerCase();
// Check if it starts with "text/"
if (normalized.startsWith("text/")) {
return true;
}
// Common text mimetypes and suffixes
return [
"application/json",
"application/xml",
"application/javascript",
"application/yaml",
"+json",
"+xml",
"+yaml",
"+text",
].some((textType) => normalized === textType || normalized.endsWith(textType));
}
export function getMimeTypeFromContentType(contentType: string): MimeType {
try {
return new MimeType(contentType);
} catch {
return new MimeType("text/plain");
}
}