fix(memo): sanitize the tag used in memo export file names
This commit is contained in:
parent
5fef311575
commit
95aa95e986
3 changed files with 112 additions and 3 deletions
35
apps/desktop/src/main/services/memo/memo-export-file-name.ts
Normal file
35
apps/desktop/src/main/services/memo/memo-export-file-name.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// src/main/services/memo/memo-export-file-name.ts
|
||||
// 메모 내보내기 파일명 정책 (순수 함수). 태그는 자유 텍스트이고 폰 동기화로도 들어오므로
|
||||
// 경로 구분자·NTFS 예약 문자·제어 문자를 그대로 파일명에 넣으면 하위 폴더 ENOENT,
|
||||
// NTFS 대체 데이터 스트림(':'), exports 폴더 이탈('..')이 생긴다. 여기서 한 번에 막는다.
|
||||
|
||||
/** 파일명에 들어갈 태그 조각의 최대 길이(코드 포인트 기준). */
|
||||
export const MEMO_EXPORT_TAG_MAX_LENGTH = 64
|
||||
|
||||
// Windows 예약 문자 + 경로 구분자 + C0/DEL 제어 문자
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const UNSAFE_FILE_NAME_CHARS = /[\\/:*?"<>|\u0000-\u001f\u007f]/g
|
||||
|
||||
/**
|
||||
* 태그를 단일 파일명 세그먼트로 안전하게 바꾼다.
|
||||
* 결과가 비면 빈 문자열을 돌려주고, 호출자는 태그 접미사를 생략한다.
|
||||
*/
|
||||
export function sanitizeMemoExportTag(tag: string): string {
|
||||
const replaced = tag
|
||||
.normalize('NFC')
|
||||
.replace(UNSAFE_FILE_NAME_CHARS, '_')
|
||||
.replace(/\s+/g, '_')
|
||||
.replace(/\.{2,}/g, '.')
|
||||
.replace(/_+/g, '_')
|
||||
.replace(/^[._]+|[._]+$/g, '')
|
||||
|
||||
const capped = Array.from(replaced).slice(0, MEMO_EXPORT_TAG_MAX_LENGTH).join('')
|
||||
return capped.replace(/[._]+$/g, '')
|
||||
}
|
||||
|
||||
/** `memo[_<safe-tag>]_<timestamp>.md` 형식의 파일명을 만든다. */
|
||||
export function buildMemoExportFileName(tag: string | undefined, timestamp: number): string {
|
||||
const safeTag = tag ? sanitizeMemoExportTag(tag) : ''
|
||||
const tagSuffix = safeTag ? `_${safeTag}` : ''
|
||||
return `memo${tagSuffix}_${timestamp}.md`
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue