Skip to content

Commit 97b50e8

Browse files
committed
Require Node.js 18 and use more recent Unicode data
Fixes #46
1 parent f6e70c4 commit 97b50e8

File tree

6 files changed

+32
-38
lines changed

6 files changed

+32
-38
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ jobs:
1212
node-version:
1313
- 20
1414
- 18
15-
- 16
1615
steps:
17-
- uses: actions/checkout@v3
18-
- uses: actions/setup-node@v3
16+
- uses: actions/checkout@v4
17+
- uses: actions/setup-node@v4
1918
with:
2019
node-version: ${{ matrix.node-version }}
2120
- run: npm install

index.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ export type Options = {
33
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).
44
55
@default true
6+
7+
> 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.__
8+
> - http://www.unicode.org/reports/tr11/
69
*/
710
readonly ambiguousIsNarrow?: boolean;
811

index.js

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,25 @@
11
import stripAnsi from 'strip-ansi';
2-
import eastAsianWidth from 'eastasianwidth';
2+
import {eastAsianWidth} from 'get-east-asian-width';
33
import emojiRegex from 'emoji-regex';
44

5-
export default function stringWidth(string, options) {
5+
export default function stringWidth(string, options = {}) {
66
if (typeof string !== 'string' || string.length === 0) {
77
return 0;
88
}
99

10-
options = {
11-
ambiguousIsNarrow: true,
12-
countAnsiEscapeCodes: false,
13-
...options,
14-
};
10+
const {
11+
ambiguousIsNarrow = true,
12+
countAnsiEscapeCodes = false,
13+
} = options;
1514

16-
if (!options.countAnsiEscapeCodes) {
15+
if (!countAnsiEscapeCodes) {
1716
string = stripAnsi(string);
1817
}
1918

2019
if (string.length === 0) {
2120
return 0;
2221
}
2322

24-
const ambiguousCharacterWidth = options.ambiguousIsNarrow ? 1 : 2;
2523
let width = 0;
2624

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

45-
const code = eastAsianWidth.eastAsianWidth(character);
46-
switch (code) {
47-
case 'F':
48-
case 'W': {
49-
width += 2;
50-
break;
51-
}
52-
53-
case 'A': {
54-
width += ambiguousCharacterWidth;
55-
break;
56-
}
57-
58-
default: {
59-
width += 1;
60-
}
61-
}
43+
width += eastAsianWidth(codePoint, {ambiguousAsWide: !ambiguousIsNarrow});
6244
}
6345

6446
return width;

package.json

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111
"url": "https://sindresorhus.com"
1212
},
1313
"type": "module",
14-
"exports": "./index.js",
14+
"exports": {
15+
"types": "./index.d.ts",
16+
"default": "./index.js"
17+
},
1518
"engines": {
16-
"node": ">=16"
19+
"node": ">=18"
1720
},
1821
"scripts": {
1922
"test": "xo && ava && tsd"
@@ -44,16 +47,17 @@
4447
"chinese",
4548
"japanese",
4649
"korean",
47-
"fixed-width"
50+
"fixed-width",
51+
"east-asian-width"
4852
],
4953
"dependencies": {
50-
"eastasianwidth": "^0.2.0",
51-
"emoji-regex": "^10.2.1",
52-
"strip-ansi": "^7.0.1"
54+
"emoji-regex": "^10.3.0",
55+
"get-east-asian-width": "^1.0.0",
56+
"strip-ansi": "^7.1.0"
5357
},
5458
"devDependencies": {
55-
"ava": "^5.2.0",
56-
"tsd": "^0.28.1",
57-
"xo": "^0.54.2"
59+
"ava": "^5.3.1",
60+
"tsd": "^0.29.0",
61+
"xo": "^0.56.0"
5862
}
5963
}

readme.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ Default: `true`
4848

4949
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).
5050

51+
> 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.**
52+
> - http://www.unicode.org/reports/tr11/
53+
5154
##### countAnsiEscapeCodes
5255

5356
Type: `boolean`\
@@ -60,3 +63,4 @@ Whether [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code) shou
6063
- [string-width-cli](https://github.com/sindresorhus/string-width-cli) - CLI for this module
6164
- [string-length](https://github.com/sindresorhus/string-length) - Get the real length of a string
6265
- [widest-line](https://github.com/sindresorhus/widest-line) - Get the visual width of the widest line in a string
66+
- [get-east-asian-width](https://github.com/sindresorhus/get-east-asian-width) - Determine the East Asian Width of a Unicode character

test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import test from 'ava';
22
import stringWidth from './index.js';
33

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

2729
test('ignores control characters', t => {

0 commit comments

Comments
 (0)