35 lines
1.6 KiB
TypeScript
35 lines
1.6 KiB
TypeScript
// 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`
|
|
}
|