import stripAnsi from 'strip-ansi'; import {eastAsianWidth} from 'get-east-asian-width'; import emojiRegex from 'emoji-regex'; const segmenter = new Intl.Segmenter(); export default function stringWidth(string, options = {}) { if (typeof string !== 'string' || string.length === 0) { return 0; } const { ambiguousIsNarrow = true, countAnsiEscapeCodes = false, } = options; if (!countAnsiEscapeCodes) { string = stripAnsi(string); } if (string.length === 0) { return 0; } let width = 0; const eastAsianWidthOptions = {ambiguousAsWide: !ambiguousIsNarrow}; for (const {segment: character} of segmenter.segment(string)) { const codePoint = character.codePointAt(0); // Ignore control characters if (codePoint <= 0x1F || (codePoint >= 0x7F && codePoint <= 0x9F)) { continue; } // Ignore combining characters if (codePoint >= 0x3_00 && codePoint <= 0x3_6F) { continue; } if (emojiRegex().test(character)) { width += 2; continue; } width += eastAsianWidth(codePoint, eastAsianWidthOptions); } return width; }