Files
2026-02-19 22:18:01 +00:00

195 lines
6.7 KiB
TypeScript

/**
* Unified language mapping for all editor implementations.
* Maps file extensions to language IDs for Monaco, CodeMirror, and lowlight.
*/
type LanguageIds = {
monaco: string;
codemirror: string;
lowlight: string;
};
const LANGUAGE_MAP: Record<string, LanguageIds> = {
// JavaScript/TypeScript
".js": { monaco: "javascript", codemirror: "javascript", lowlight: "javascript" },
".mjs": { monaco: "javascript", codemirror: "javascript", lowlight: "javascript" },
".cjs": { monaco: "javascript", codemirror: "javascript", lowlight: "javascript" },
".jsx": { monaco: "javascript", codemirror: "jsx", lowlight: "javascript" },
".ts": { monaco: "typescript", codemirror: "typescript", lowlight: "typescript" },
".mts": { monaco: "typescript", codemirror: "typescript", lowlight: "typescript" },
".cts": { monaco: "typescript", codemirror: "typescript", lowlight: "typescript" },
".tsx": { monaco: "typescript", codemirror: "tsx", lowlight: "typescript" },
// Python
".py": { monaco: "python", codemirror: "python", lowlight: "python" },
".pyw": { monaco: "python", codemirror: "python", lowlight: "python" },
".pyi": { monaco: "python", codemirror: "python", lowlight: "python" },
// Go
".go": { monaco: "go", codemirror: "go", lowlight: "go" },
// Rust
".rs": { monaco: "rust", codemirror: "rust", lowlight: "rust" },
// Ruby
".rb": { monaco: "ruby", codemirror: "ruby", lowlight: "ruby" },
".erb": { monaco: "ruby", codemirror: "ruby", lowlight: "erb" },
// Java/JVM
".java": { monaco: "java", codemirror: "java", lowlight: "java" },
".kt": { monaco: "kotlin", codemirror: "kotlin", lowlight: "kotlin" },
".kts": { monaco: "kotlin", codemirror: "kotlin", lowlight: "kotlin" },
".scala": { monaco: "scala", codemirror: "scala", lowlight: "scala" },
".groovy": { monaco: "groovy", codemirror: "groovy", lowlight: "groovy" },
// Swift
".swift": { monaco: "swift", codemirror: "swift", lowlight: "swift" },
// C/C++
".c": { monaco: "c", codemirror: "cpp", lowlight: "c" },
".h": { monaco: "c", codemirror: "cpp", lowlight: "c" },
".cpp": { monaco: "cpp", codemirror: "cpp", lowlight: "cpp" },
".cc": { monaco: "cpp", codemirror: "cpp", lowlight: "cpp" },
".cxx": { monaco: "cpp", codemirror: "cpp", lowlight: "cpp" },
".hpp": { monaco: "cpp", codemirror: "cpp", lowlight: "cpp" },
".hxx": { monaco: "cpp", codemirror: "cpp", lowlight: "cpp" },
// C#
".cs": { monaco: "csharp", codemirror: "csharp", lowlight: "csharp" },
// PHP
".php": { monaco: "php", codemirror: "php", lowlight: "php" },
// Web
".html": { monaco: "html", codemirror: "html", lowlight: "xml" },
".htm": { monaco: "html", codemirror: "html", lowlight: "xml" },
".css": { monaco: "css", codemirror: "css", lowlight: "css" },
".scss": { monaco: "scss", codemirror: "css", lowlight: "scss" },
".sass": { monaco: "scss", codemirror: "css", lowlight: "scss" },
".less": { monaco: "less", codemirror: "css", lowlight: "less" },
// Data formats
".json": { monaco: "json", codemirror: "json", lowlight: "json" },
".jsonc": { monaco: "json", codemirror: "json", lowlight: "json" },
".yaml": { monaco: "yaml", codemirror: "yaml", lowlight: "yaml" },
".yml": { monaco: "yaml", codemirror: "yaml", lowlight: "yaml" },
".xml": { monaco: "xml", codemirror: "html", lowlight: "xml" },
".toml": { monaco: "ini", codemirror: "toml", lowlight: "ini" },
".ini": { monaco: "ini", codemirror: "ini", lowlight: "ini" },
".env": { monaco: "ini", codemirror: "properties", lowlight: "ini" },
// Markup
".md": { monaco: "markdown", codemirror: "markdown", lowlight: "markdown" },
".mdx": { monaco: "markdown", codemirror: "markdown", lowlight: "markdown" },
// Shell
".sh": { monaco: "shell", codemirror: "bash", lowlight: "bash" },
".bash": { monaco: "shell", codemirror: "bash", lowlight: "bash" },
".zsh": { monaco: "shell", codemirror: "bash", lowlight: "bash" },
".fish": { monaco: "shell", codemirror: "fish", lowlight: "bash" },
// SQL
".sql": { monaco: "sql", codemirror: "sql", lowlight: "sql" },
// Docker
".dockerfile": { monaco: "dockerfile", codemirror: "dockerfile", lowlight: "dockerfile" },
// GraphQL
".graphql": { monaco: "graphql", codemirror: "graphql", lowlight: "graphql" },
".gql": { monaco: "graphql", codemirror: "graphql", lowlight: "graphql" },
// Vue/Svelte
".vue": { monaco: "html", codemirror: "vue", lowlight: "xml" },
".svelte": { monaco: "html", codemirror: "svelte", lowlight: "xml" },
};
/**
* Language name aliases (used when a language string is provided instead of file ext).
* Maps common language names to Monaco language IDs.
*/
const LANGUAGE_ALIASES: Record<string, string> = {
javascript: "javascript",
js: "javascript",
jsx: "javascript",
typescript: "typescript",
ts: "typescript",
tsx: "typescript",
python: "python",
py: "python",
go: "go",
golang: "go",
rust: "rust",
rs: "rust",
java: "java",
kotlin: "kotlin",
scala: "scala",
swift: "swift",
c: "c",
cpp: "cpp",
"c++": "cpp",
csharp: "csharp",
"c#": "csharp",
php: "php",
ruby: "ruby",
rb: "ruby",
html: "html",
css: "css",
scss: "scss",
less: "less",
json: "json",
yaml: "yaml",
yml: "yaml",
xml: "xml",
markdown: "markdown",
md: "markdown",
bash: "shell",
shell: "shell",
sh: "shell",
zsh: "shell",
sql: "sql",
dockerfile: "dockerfile",
graphql: "graphql",
plaintext: "plaintext",
text: "plaintext",
};
function getExtension(filePath: string): string {
const lastSlash = filePath.lastIndexOf("/");
const name = lastSlash >= 0 ? filePath.slice(lastSlash + 1) : filePath;
// Handle Dockerfile (no extension)
if (name.toLowerCase() === "dockerfile") return ".dockerfile";
const dot = name.lastIndexOf(".");
if (dot === -1) return "";
return name.slice(dot).toLowerCase();
}
export function getMonacoLanguage(filePath: string): string {
const ext = getExtension(filePath);
return LANGUAGE_MAP[ext]?.monaco ?? "plaintext";
}
export function getMonacoLanguageFromName(language: string): string {
return LANGUAGE_ALIASES[language.toLowerCase()] ?? "plaintext";
}
export function getLowlightLanguage(filePath: string): string {
const ext = getExtension(filePath);
return LANGUAGE_MAP[ext]?.lowlight ?? "plaintext";
}
export function getLowlightLanguageFromName(language: string): string {
// For lowlight, the language name is typically the same
const lower = language.toLowerCase();
// Try to find via alias → then look it up in the map values
const monacoLang = LANGUAGE_ALIASES[lower];
if (!monacoLang) return lower;
// Find a matching entry in the map
for (const ids of Object.values(LANGUAGE_MAP)) {
if (ids.monaco === monacoLang) return ids.lowlight;
}
return lower;
}