wiki-filename.ts 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. export function makeSafeFileSlug(title: string, fallback = "untitled"): string {
  2. const slug = title
  3. .normalize("NFKC")
  4. .trim()
  5. .replace(/\s+/g, "-")
  6. .replace(/[\\/:*?"<>|]/g, "-")
  7. .replace(/[^\p{L}\p{N}._-]/gu, "")
  8. .replace(/-+/g, "-")
  9. .replace(/^-|-$/g, "")
  10. .slice(0, 80)
  11. return slug.length > 0 ? slug : fallback
  12. }
  13. function stripChapterPrefix(title: string): string {
  14. const normalized = title.normalize("NFKC").trim()
  15. return normalized
  16. .replace(/^第\s*(?:\d+|[零〇一二三四五六七八九十百千万两]+)\s*[章节卷回]\s*[-_::,、.。]?\s*/, "")
  17. .trim()
  18. }
  19. export function makeDefaultChapterTitle(chapterNumber: number, chapterName = ""): string {
  20. const normalizedNumber = Math.max(1, Math.trunc(chapterNumber))
  21. const cleanedName = stripChapterPrefix(chapterName)
  22. return cleanedName ? `第${normalizedNumber}章-${cleanedName}` : `第${normalizedNumber}章`
  23. }
  24. export function makeChapterFileStem(title: string, chapterNumber?: number | null): string {
  25. const cleanTitle = title.normalize("NFKC").trim()
  26. if (typeof chapterNumber === "number" && Number.isFinite(chapterNumber) && chapterNumber > 0) {
  27. const namePart = stripChapterPrefix(cleanTitle)
  28. const safeName = namePart ? makeSafeFileSlug(namePart) : ""
  29. return safeName ? `第${chapterNumber}章-${safeName}` : `第${chapterNumber}章`
  30. }
  31. return makeSafeFileSlug(cleanTitle)
  32. }
  33. export function makeChapterFileName(title: string, chapterNumber?: number | null): string {
  34. return `${makeChapterFileStem(title, chapterNumber)}.md`
  35. }