From 08bd1ad61abef13a2d370e94ed2ea17299ae721d Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:09:16 +0530 Subject: [PATCH] feat: Add `fileNameWithEllipsis` helper (#34) --- package.json | 2 +- src/helpers.ts | 31 +++++++++++++++++++++++++++++ test/helpers.test.ts | 47 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3beead9..a788412 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@chatwoot/utils", - "version": "0.0.25", + "version": "0.0.26", "description": "Chatwoot utils", "private": false, "license": "MIT", diff --git a/src/helpers.ts b/src/helpers.ts index a0cb504..8660c8e 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -119,3 +119,34 @@ export const convertSecondsToTimeUnit = ( return { time: Number((seconds / 3600).toFixed(1)), unit: unitNames.hour }; return { time: Number((seconds / 86400).toFixed(1)), unit: unitNames.day }; }; + +/** + * @name fileNameWithEllipsis + * @description Truncates a filename while preserving the extension + * @param {Object} file - File object containing filename or name property + * @param {number} [maxLength=26] - Maximum length of the filename (excluding extension) + * @param {string} [ellipsis='…'] - Character to use for truncation + * @returns {string} Truncated filename with extension + * @example + * fileNameWithEllipsis({ filename: 'very-long-filename.pdf' }, 10) // 'very-long-f….pdf' + * fileNameWithEllipsis({ name: 'short.txt' }, 10) // 'short.txt' + */ +export const fileNameWithEllipsis = ( + file: { filename?: string; name?: string }, + maxLength: number = 26, + ellipsis: string = '…' +): string => { + const fullName = file?.filename ?? file?.name ?? 'Untitled'; + + const dotIndex = fullName.lastIndexOf('.'); + if (dotIndex === -1) return fullName; + + const [name, extension] = [ + fullName.slice(0, dotIndex), + fullName.slice(dotIndex), + ]; + + if (name.length <= maxLength) return fullName; + + return `${name.slice(0, maxLength)}${ellipsis}${extension}`; +}; diff --git a/test/helpers.test.ts b/test/helpers.test.ts index 36db1e2..ea14b88 100644 --- a/test/helpers.test.ts +++ b/test/helpers.test.ts @@ -1,4 +1,4 @@ -import { convertSecondsToTimeUnit } from '../src/helpers'; +import { convertSecondsToTimeUnit, fileNameWithEllipsis } from '../src/helpers'; describe('#convertSecondsToTimeUnit', () => { it("it should return { time: 1, unit: 'm' } if 60 seconds passed", () => { @@ -49,3 +49,48 @@ describe('#convertSecondsToTimeUnit', () => { ).toEqual({ time: '', unit: '' }); }); }); + +describe('fileNameWithEllipsis', () => { + it('should return original filename if name length is within limit', () => { + const file = { name: 'document.pdf' }; + expect(fileNameWithEllipsis(file)).toBe('document.pdf'); + }); + + it('should truncate filename if it exceeds max length', () => { + const file = { name: 'very-long-filename-that-needs-truncating.pdf' }; + expect(fileNameWithEllipsis(file)).toBe('very-long-filename-that-ne….pdf'); + }); + + it('should handle files without extension', () => { + const file = { name: 'README' }; + expect(fileNameWithEllipsis(file)).toBe('README'); + }); + + it('should handle files with multiple dots', () => { + const file = { name: 'archive.tar.gz' }; + expect(fileNameWithEllipsis(file)).toBe('archive.tar.gz'); + }); + + it('should handle hidden files', () => { + const file = { name: '.gitignore' }; + expect(fileNameWithEllipsis(file)).toBe('.gitignore'); + }); + + it('should handle both filename and name properties', () => { + const file = { + filename: 'from-filename.pdf', + name: 'from-name.pdf', + }; + expect(fileNameWithEllipsis(file)).toBe('from-filename.pdf'); + }); + + it('should handle special characters', () => { + const file = { name: 'résumé-2023_final-version.doc' }; + expect(fileNameWithEllipsis(file)).toBe('résumé-2023_final-version.doc'); + }); + + it('should handle very short filenames', () => { + const file = { name: 'a.txt' }; + expect(fileNameWithEllipsis(file)).toBe('a.txt'); + }); +});