This commit is contained in:
2026-09-12 14:15:26 +08:00
commit 9c06d3f4be
99 changed files with 41853 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
// 文件系统 errno → 用户能看懂的提示main + renderer 共享)
// ============================================================================
//
// 单一事实源。解决 Round 3 之前的三份独立实现漂移:
// - main/file-ops.js#friendlyWriteError(e) —— 主进程内部,签名 e.code
// - src/app.js#friendlyWriteError(code, fallback) —— renderer save 路径
// - src/file-ops.js#friendlyFsError(code, fallback) —— renderer 文件 CRUD
//
// 三份在 EROFS / ENAMETOOLONG / ENOTDIR / ENOTEMPTY 上文案不同 —— 用户看到
// 不一致提示。每加一个 errno 都要同步改三处,每处都有人漏改。
//
// 修法Round 4 收尾):本文件 CJS export 函数 friendlyFsError(code, fallback)
// - main/file-ops.js 用 require('./shared/friendly-fs-error.js')
// 调用时友好FsError(e?.code, e?.message || '写入文件失败')
// - preload 用 require + contextBridge 暴露 window.api.friendlyFsError
// renderer 端走 window.api.friendlyFsError(...) 拿到同一份文案
//
// 加载方式:
// - main.js / main/file-ops.js / preload.js (CJS)const { friendlyFsError } = require('...')
// - renderer经 preload contextBridge 过桥window.api.friendlyFsError
// —— renderer 跑在 Chromium 原生 ESM不能直接 import CJS
//
// 【fallback 行为】
// - 已知 errno返回固定中文文案与 fileOps.friendlyFsError 测试矩阵对齐)
// - 未知 errno返回 fallback业务码如 PATH_NOT_ALLOWED / SYMLINK_NOT_ALLOWED /
// FILE_TOO_LARGE / FILE_CHANGED_EXTERNALLY 等不是 fs errno由 IPC 调用方
// 把 result.message 中文文案塞进 fallback
// - fallback 为空串 / undefined走兜底「未知错误」避免空 toast
// ============================================================================
'use strict';
/**
* 把后端返回的 errno 翻译成中文用户提示。
*
* @param {string|null|undefined} code - 原始 errnoEACCES / EPERM / ENOSPC ...
* 或业务码字符串PATH_NOT_ALLOWED 等),业务码一律走 fallback
* @param {string|undefined} fallback - errno 未匹配时使用的回退文案
* (主进程一般传 e?.messagerenderer 一般传 IPC result.message / result.error
* @returns {string} 中文提示(永不为空 —— 兜底走「未知错误」)
*/
function friendlyFsError(code, fallback) {
switch (code) {
case 'EACCES':
case 'EPERM':
return '文件被占用或没有写入权限(可能是只读文件 / 另一进程独占 / 权限不足)';
case 'ENOSPC':
return '磁盘空间不足';
case 'EROFS':
return '只读文件系统,无法写入';
case 'EIO':
return '磁盘 I/O 错误';
case 'EBUSY':
return '文件被其他程序占用';
case 'ENAMETOOLONG':
return '路径过长';
case 'ENOTDIR':
return '父目录不是目录';
case 'EISDIR':
return '目标路径是文件夹,无法写入';
case 'ENOTEMPTY':
return '目标文件夹不为空';
// audit fix (Settings P3 / ENOENT mapping):原本 ENOENT 没在 mapping 里,
// 走 default → fallback 兜底成「未知错误」。ENOENT 是最常见的 fs errno
// 之一rename 源文件已删 / delete 已被外部删 / 路径打错 / watch 到一半
// 文件被替换),用户看到一个空泛"未知错误"会以为 Notes 出 bug。补上。
// 措辞区分「文件不存在」与「路径里某一级目录不存在」也覆盖 ENOTDIR
// 已有的 case —— ENOENT 统一按"目标路径不存在"处理(精确到「文件还是
// 目录」要 main 端自己抛业务码,不该让 errno mapping 揣测)。
case 'ENOENT':
return '文件或目录不存在(可能已被移动、重命名或删除)';
default:
return fallback || '未知错误';
}
}
module.exports = { friendlyFsError };