trimSlug.tsx 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. /**
  2. * Trim slug name with a preference for preserving whole words. Only cut up
  3. * whole words if the last remaining words are still too long. For example:
  4. * "javascript-project-backend" --> "javascript…backend"
  5. * "my-long-sentry-project-name" --> "my-long…project-name"
  6. * "javascriptproject-backend" --> "javascriptproj…ackend"
  7. */
  8. export function trimSlug(slug: string, maxLength: number = 20) {
  9. // Return the original slug if it's already shorter than maxLength
  10. if (slug.length <= maxLength) {
  11. return slug;
  12. }
  13. /**
  14. * Array of words inside the slug.
  15. * E.g. "my-project-name" becomes ["my", "project", "name"]
  16. */
  17. const words: string[] = slug.split('-');
  18. // If the string is too long but not hyphenated, return an end-trimmed
  19. // string. E.g. "javascriptfrontendproject" --> "javascriptfrontendp…"
  20. if (words.length === 1) {
  21. return `${slug.slice(0, maxLength - 1)}\u2026`;
  22. }
  23. /**
  24. * Returns the length (total number of letters plus hyphens in between
  25. * words) of the current words array.
  26. */
  27. function getLength(arr: string[]): number {
  28. return arr.reduce((acc, cur) => acc + cur.length + 1, 0) - 1;
  29. }
  30. // Progressively remove words in the middle until we're below maxLength,
  31. // or when only two words are left
  32. while (getLength(words) > maxLength && words.length > 2) {
  33. words.splice(Math.floor(words.length / 2 - 0.5), 1);
  34. }
  35. // If the remaining words array satisfies the maxLength requirement,
  36. // return the trimmed result.
  37. if (getLength(words) <= maxLength) {
  38. const divider = Math.floor(words.length / 2);
  39. return `${words.slice(0, divider).join('-')}\u2026${words.slice(divider).join('-')}`;
  40. }
  41. // If the remaining 2 words are still too long, trim those words starting
  42. // from the middle.
  43. const debt = getLength(words) - maxLength;
  44. const toTrimFromLeftWord = Math.ceil(debt / 2);
  45. const leftWordLength = Math.max(words[0].length - toTrimFromLeftWord, 3);
  46. const leftWord = words[0].slice(0, leftWordLength);
  47. const rightWordLength = maxLength - leftWord.length;
  48. const rightWord = words[1].slice(-rightWordLength);
  49. return `${leftWord}\u2026${rightWord}`;
  50. }