Files
oci-portal-dash/src/components/objectstorage/codeHighlight.ts
T

95 lines
3.3 KiB
TypeScript

import type { LanguageFn } from 'highlight.js'
const IMAGE_EXT = new Set(['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp', 'ico', 'avif'])
const TEXT_EXT = new Set([
'txt', 'md', 'log', 'json', 'yaml', 'yml', 'ini', 'toml', 'conf', 'cfg', 'csv',
'xml', 'html', 'htm', 'css', 'js', 'ts', 'sh', 'py', 'go', 'env', 'properties', 'sql',
])
/** office/pdf 预览形态(vue-office 渲染);doc/xls/ppt 老格式不支持 */
const OFFICE_KIND: Record<string, 'docx' | 'xlsx' | 'pdf' | 'pptx'> = {
docx: 'docx',
xlsx: 'xlsx',
pdf: 'pdf',
pptx: 'pptx',
}
export type PreviewKind = 'image' | 'text' | 'docx' | 'xlsx' | 'pdf' | 'pptx' | 'none'
export function extOf(name: string): string {
return name.split('.').pop()?.toLowerCase() ?? ''
}
/** 对象是否支持预览及预览形态 */
export function previewKindOf(name: string): PreviewKind {
const ext = extOf(name)
// svg 按文本处理:预览「渲染 ↔ 代码」双态由文本生成,且可在线编辑
if (ext === 'svg') return 'text'
if (IMAGE_EXT.has(ext)) return 'image'
if (TEXT_EXT.has(ext)) return 'text'
return OFFICE_KIND[ext] ?? 'none'
}
/** 扩展名 → highlight.js 语言;不在表内的按纯文本展示 */
const EXT_LANG: Record<string, string> = {
py: 'python',
json: 'json',
yaml: 'yaml',
yml: 'yaml',
ini: 'ini',
toml: 'ini',
conf: 'ini',
cfg: 'ini',
env: 'ini',
properties: 'ini',
xml: 'xml',
html: 'xml',
htm: 'xml',
sh: 'bash',
js: 'javascript',
ts: 'typescript',
go: 'go',
sql: 'sql',
md: 'markdown',
css: 'css',
svg: 'xml',
}
/** 语言按需动态加载,各自成 chunk,不预览不下载 */
const LANG_LOADERS: Record<string, () => Promise<{ default: LanguageFn }>> = {
python: () => import('highlight.js/lib/languages/python'),
json: () => import('highlight.js/lib/languages/json'),
yaml: () => import('highlight.js/lib/languages/yaml'),
ini: () => import('highlight.js/lib/languages/ini'),
xml: () => import('highlight.js/lib/languages/xml'),
bash: () => import('highlight.js/lib/languages/bash'),
javascript: () => import('highlight.js/lib/languages/javascript'),
typescript: () => import('highlight.js/lib/languages/typescript'),
go: () => import('highlight.js/lib/languages/go'),
sql: () => import('highlight.js/lib/languages/sql'),
markdown: () => import('highlight.js/lib/languages/markdown'),
css: () => import('highlight.js/lib/languages/css'),
}
/**
* 高亮一段代码;lang 可传语言名(md 围栏标签,如 python/bash)或扩展名(如 py/sh)。
* 返回 hljs 生成的 HTML(输入已转义,可安全 v-html);不支持或失败返回 null。
*/
export async function highlightCode(code: string, lang: string): Promise<string | null> {
const name = LANG_LOADERS[lang] ? lang : EXT_LANG[lang]
const load = name ? LANG_LOADERS[name] : undefined
if (!name || !load) return null
try {
const { default: hljs } = await import('highlight.js/lib/core')
if (!hljs.getLanguage(name)) hljs.registerLanguage(name, (await load()).default)
return hljs.highlight(code, { language: name }).value
} catch {
return null
}
}
/** 按扩展名高亮整份源码,语义同 highlightCode(ext 分支)。 */
export async function highlightSource(text: string, ext: string): Promise<string | null> {
return highlightCode(text, ext)
}