Skip to content

Commit

Permalink
Require Node.js 18 and use more recent Unicode data
Browse files Browse the repository at this point in the history
Fixes #46
  • Loading branch information
sindresorhus committed Oct 28, 2023
1 parent f6e70c4 commit 97b50e8
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 38 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/main.yml
Expand Up @@ -12,10 +12,9 @@ jobs:
node-version:
- 20
- 18
- 16
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
3 changes: 3 additions & 0 deletions index.d.ts
Expand Up @@ -3,6 +3,9 @@ export type Options = {
Count [ambiguous width characters](https://www.unicode.org/reports/tr11/#Ambiguous) as having narrow width (count of 1) instead of wide width (count of 2).
@default true
> Ambiguous characters behave like wide or narrow characters depending on the context (language tag, script identification, associated font, source of data, or explicit markup; all can provide the context). __If the context cannot be established reliably, they should be treated as narrow characters by default.__
> - http://www.unicode.org/reports/tr11/
*/
readonly ambiguousIsNarrow?: boolean;

Expand Down
34 changes: 8 additions & 26 deletions index.js
@@ -1,27 +1,25 @@
import stripAnsi from 'strip-ansi';
import eastAsianWidth from 'eastasianwidth';
import {eastAsianWidth} from 'get-east-asian-width';
import emojiRegex from 'emoji-regex';

export default function stringWidth(string, options) {
export default function stringWidth(string, options = {}) {
if (typeof string !== 'string' || string.length === 0) {
return 0;
}

options = {
ambiguousIsNarrow: true,
countAnsiEscapeCodes: false,
...options,
};
const {
ambiguousIsNarrow = true,
countAnsiEscapeCodes = false,
} = options;

if (!options.countAnsiEscapeCodes) {
if (!countAnsiEscapeCodes) {
string = stripAnsi(string);
}

if (string.length === 0) {
return 0;
}

const ambiguousCharacterWidth = options.ambiguousIsNarrow ? 1 : 2;
let width = 0;

for (const {segment: character} of new Intl.Segmenter().segment(string)) {
Expand All @@ -42,23 +40,7 @@ export default function stringWidth(string, options) {
continue;
}

const code = eastAsianWidth.eastAsianWidth(character);
switch (code) {
case 'F':
case 'W': {
width += 2;
break;
}

case 'A': {
width += ambiguousCharacterWidth;
break;
}

default: {
width += 1;
}
}
width += eastAsianWidth(codePoint, {ambiguousAsWide: !ambiguousIsNarrow});
}

return width;
Expand Down
22 changes: 13 additions & 9 deletions package.json
Expand Up @@ -11,9 +11,12 @@
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": "./index.js",
"exports": {
"types": "./index.d.ts",
"default": "./index.js"
},
"engines": {
"node": ">=16"
"node": ">=18"
},
"scripts": {
"test": "xo && ava && tsd"
Expand Down Expand Up @@ -44,16 +47,17 @@
"chinese",
"japanese",
"korean",
"fixed-width"
"fixed-width",
"east-asian-width"
],
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^10.2.1",
"strip-ansi": "^7.0.1"
"emoji-regex": "^10.3.0",
"get-east-asian-width": "^1.0.0",
"strip-ansi": "^7.1.0"
},
"devDependencies": {
"ava": "^5.2.0",
"tsd": "^0.28.1",
"xo": "^0.54.2"
"ava": "^5.3.1",
"tsd": "^0.29.0",
"xo": "^0.56.0"
}
}
4 changes: 4 additions & 0 deletions readme.md
Expand Up @@ -48,6 +48,9 @@ Default: `true`

Count [ambiguous width characters](https://www.unicode.org/reports/tr11/#Ambiguous) as having narrow width (count of 1) instead of wide width (count of 2).

> Ambiguous characters behave like wide or narrow characters depending on the context (language tag, script identification, associated font, source of data, or explicit markup; all can provide the context). **If the context cannot be established reliably, they should be treated as narrow characters by default.**
> - http://www.unicode.org/reports/tr11/
##### countAnsiEscapeCodes

Type: `boolean`\
Expand All @@ -60,3 +63,4 @@ Whether [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code) shou
- [string-width-cli](https://github.com/sindresorhus/string-width-cli) - CLI for this module
- [string-length](https://github.com/sindresorhus/string-length) - Get the real length of a string
- [widest-line](https://github.com/sindresorhus/widest-line) - Get the visual width of the widest line in a string
- [get-east-asian-width](https://github.com/sindresorhus/get-east-asian-width) - Determine the East Asian Width of a Unicode character
2 changes: 2 additions & 0 deletions test.js
Expand Up @@ -2,6 +2,7 @@ import test from 'ava';
import stringWidth from './index.js';

test('main', t => {
t.is(stringWidth('⛣', {ambiguousIsNarrow: false}), 2);
t.is(stringWidth('abcde'), 5);
t.is(stringWidth('古池や'), 6);
t.is(stringWidth('あいうabc'), 9);
Expand All @@ -22,6 +23,7 @@ test('main', t => {
t.is(stringWidth('\u{845B}\u{E0100}'), 2, 'Variation Selectors');
t.is(stringWidth('ปฏัก'), 3, 'Thai script');
t.is(stringWidth('_\u0E34'), 1, 'Thai script');
t.is(stringWidth('“', {ambiguousIsNarrow: false}), 2);
});

test('ignores control characters', t => {
Expand Down

0 comments on commit 97b50e8

Please sign in to comment.