'use strict'; const sliceAnsi = require('slice-ansi'); const stringWidth = require('string-width'); function getIndexOfNearestSpace(string, index, shouldSearchRight) { if (string.charAt(index) === ' ') { return index; } for (let i = 1; i <= 3; i++) { if (shouldSearchRight) { if (string.charAt(index + i) === ' ') { return index + i; } } else if (string.charAt(index - i) === ' ') { return index - i; } } return index; } module.exports = (text, columns, options) => { options = { position: 'end', preferTruncationOnSpace: false, ...options }; const {position, space, preferTruncationOnSpace} = options; let ellipsis = '…'; let ellipsisWidth = 1; if (typeof text !== 'string') { throw new TypeError(`Expected \`input\` to be a string, got ${typeof text}`); } if (typeof columns !== 'number') { throw new TypeError(`Expected \`columns\` to be a number, got ${typeof columns}`); } if (columns < 1) { return ''; } if (columns === 1) { return ellipsis; } const length = stringWidth(text); if (length <= columns) { return text; } if (position === 'start') { if (preferTruncationOnSpace) { const nearestSpace = getIndexOfNearestSpace(text, length - columns + 1, true); return ellipsis + sliceAnsi(text, nearestSpace, length).trim(); } if (space === true) { ellipsis += ' '; ellipsisWidth = 2; } return ellipsis + sliceAnsi(text, length - columns + ellipsisWidth, length); } if (position === 'middle') { if (space === true) { ellipsis = ' ' + ellipsis + ' '; ellipsisWidth = 3; } const half = Math.floor(columns / 2); if (preferTruncationOnSpace) { const spaceNearFirstBreakPoint = getIndexOfNearestSpace(text, half); const spaceNearSecondBreakPoint = getIndexOfNearestSpace(text, length - (columns - half) + 1, true); return sliceAnsi(text, 0, spaceNearFirstBreakPoint) + ellipsis + sliceAnsi(text, spaceNearSecondBreakPoint, length).trim(); } return ( sliceAnsi(text, 0, half) + ellipsis + sliceAnsi(text, length - (columns - half) + ellipsisWidth, length) ); } if (position === 'end') { if (preferTruncationOnSpace) { const nearestSpace = getIndexOfNearestSpace(text, columns - 1); return sliceAnsi(text, 0, nearestSpace) + ellipsis; } if (space === true) { ellipsis = ' ' + ellipsis; ellipsisWidth = 2; } return sliceAnsi(text, 0, columns - ellipsisWidth) + ellipsis; } throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${position}`); };