release: v0.6.0 — 内置解析器迁移 / Toast 全面接入 / Sqlark 深度集成
- 渲染管线迁移至 MetonaEditor 内置解析器,移除 unified/rehype 全家桶(9 个依赖) - 修复相对路径图片修复的目录前缀碰撞与路径解析 bug - ConfirmDialog/useConfirm/LoadingSpinner/useDocStats 移除,改用 MeToast.confirm/loading/promise - 新增状态栏(字数/行数/阅读时间/光标位置)、Zen 模式、数据备份导出导入 - Sqlark: 版本化迁移(addMigration/migrateTo)、subscribe 表变更、备份 exportAll/importTable - 数据库损坏自愈:异常退出残留残缺 SSTable 导致打开失败时自动重建 - 大纲导航改用 scrollToLine 官方 API - 修复 rollup 平台包互删(postinstall 自动补齐)+ 集成测试(fake-indexeddb)
This commit is contained in:
+15
-8
@@ -10,26 +10,29 @@ export async function readFileContent(filePath: string): Promise<ReadFileResult>
|
||||
try {
|
||||
const fileStat = await stat(filePath)
|
||||
if (fileStat.size > MAX_FILE_SIZE) {
|
||||
return { success: false, error: `文件过大(${(fileStat.size / 1024 / 1024).toFixed(1)} MB),暂不支持超过 20MB 的文件` }
|
||||
return {
|
||||
success: false,
|
||||
error: `文件过大(${(fileStat.size / 1024 / 1024).toFixed(1)} MB),暂不支持超过 20MB 的文件`,
|
||||
}
|
||||
}
|
||||
// L-01: 检测并剥离 BOM(UTF-8 FEFF / UTF-16 LE FFFE / UTF-16 BE FEFF)
|
||||
const buffer = await readFile(filePath)
|
||||
let content: string
|
||||
if (buffer.length >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) {
|
||||
if (buffer.length >= 2 && buffer[0] === 0xfe && buffer[1] === 0xff) {
|
||||
// UTF-16 BE: swap bytes to LE 再解码
|
||||
const swapped = Buffer.allocUnsafe(buffer.length)
|
||||
buffer.copy(swapped)
|
||||
swapped.swap16()
|
||||
content = swapped.toString('utf-16le')
|
||||
if (content.charCodeAt(0) === 0xFEFF) content = content.slice(1)
|
||||
} else if (buffer.length >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) {
|
||||
if (content.charCodeAt(0) === 0xfeff) content = content.slice(1)
|
||||
} else if (buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xfe) {
|
||||
// UTF-16 LE
|
||||
content = buffer.toString('utf-16le')
|
||||
if (content.charCodeAt(0) === 0xFEFF) content = content.slice(1)
|
||||
if (content.charCodeAt(0) === 0xfeff) content = content.slice(1)
|
||||
} else {
|
||||
// UTF-8 (含 FEFF BOM 剥离)
|
||||
content = buffer.toString('utf-8')
|
||||
if (content.charCodeAt(0) === 0xFEFF) content = content.slice(1)
|
||||
if (content.charCodeAt(0) === 0xfeff) content = content.slice(1)
|
||||
}
|
||||
return { success: true, content }
|
||||
} catch (err) {
|
||||
@@ -48,7 +51,11 @@ export async function saveFileContent(filePath: string, content: string): Promis
|
||||
return { success: true, filePath }
|
||||
} catch (err) {
|
||||
// 清理残留临时文件
|
||||
try { await unlink(tmpFile) } catch { /* ignore */ }
|
||||
try {
|
||||
await unlink(tmpFile)
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return { success: false, error: (err as Error).message }
|
||||
}
|
||||
}
|
||||
@@ -58,7 +65,7 @@ export async function buildDirTree(
|
||||
dirPath: string,
|
||||
depth = 0,
|
||||
maxDepth = 10,
|
||||
visited?: Set<string>
|
||||
visited?: Set<string>,
|
||||
): Promise<FileNode[]> {
|
||||
if (depth > maxDepth) return []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user