grapheme-conformance 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/VERIFY.md +57 -29
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
**Your string splitter is probably wrong about Hindi.**
|
|
4
4
|
|
|
5
|
+
[](https://github.com/tamerkalla/grapheme-conformance/actions/workflows/release.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/grapheme-conformance)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
[](https://www.npmjs.com/package/grapheme-conformance)
|
|
9
|
+
|
|
5
10
|
Unicode publishes `GraphemeBreakTest.txt`: a machine-readable answer key that
|
|
6
11
|
says exactly where a string may be split into user-perceived characters. This
|
|
7
12
|
package scores any JavaScript grapheme segmenter against it, tells you which
|
package/VERIFY.md
CHANGED
|
@@ -1,29 +1,50 @@
|
|
|
1
1
|
# VERIFY
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This reproduces the scoreboard's two Unicode-16.0.0-and-15.1.0 columns from the
|
|
4
|
+
published package, in a clean directory. It does not require this repository
|
|
5
|
+
to be checked out.
|
|
4
6
|
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
mkdir -p grapheme-conformance-verify && cd grapheme-conformance-verify
|
|
9
|
+
npm init -y >/dev/null 2>&1
|
|
10
|
+
npm install grapheme-conformance@latest grapheme-splitter@1.0.4 graphemer@1.4.0 runes2@1.1.4 unicode-segmenter@0.17.3 >/dev/null 2>&1
|
|
11
|
+
cat > verify.mjs <<'JS'
|
|
12
|
+
import { score, vectors } from 'grapheme-conformance';
|
|
13
|
+
import { splitGraphemes } from 'unicode-segmenter/grapheme';
|
|
14
|
+
import graphemerModule from 'graphemer';
|
|
15
|
+
import GraphemeSplitter from 'grapheme-splitter';
|
|
16
|
+
import { runes } from 'runes2';
|
|
8
17
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
const Graphemer = graphemerModule.default ?? graphemerModule;
|
|
19
|
+
const intl = new Intl.Segmenter('en', { granularity: 'grapheme' });
|
|
20
|
+
const graphemer = new Graphemer();
|
|
21
|
+
const splitter = new GraphemeSplitter();
|
|
12
22
|
|
|
13
|
-
|
|
23
|
+
const impls = {
|
|
24
|
+
'Intl.Segmenter': (s) => [...intl.segment(s)].map((p) => p.segment),
|
|
25
|
+
'unicode-segmenter': (s) => [...splitGraphemes(s)],
|
|
26
|
+
graphemer: (s) => graphemer.splitGraphemes(s),
|
|
27
|
+
'grapheme-splitter': (s) => splitter.splitGraphemes(s),
|
|
28
|
+
runes2: (s) => runes(s),
|
|
29
|
+
};
|
|
14
30
|
|
|
15
|
-
|
|
31
|
+
for (const version of ['15.1.0', '16.0.0']) {
|
|
32
|
+
const vecs = vectors[version];
|
|
33
|
+
const row = Object.entries(impls)
|
|
34
|
+
.map(([name, fn]) => `${name}=${score(fn, vecs).passed}`)
|
|
35
|
+
.join(' ');
|
|
36
|
+
console.log(`${version}: ${row}`);
|
|
37
|
+
}
|
|
38
|
+
JS
|
|
39
|
+
node verify.mjs
|
|
40
|
+
```
|
|
16
41
|
|
|
17
|
-
|
|
18
|
-
|---|---|---|
|
|
19
|
-
| `Intl.Segmenter` | 1186 | 1092 |
|
|
20
|
-
| `unicode-segmenter` | 1186 | 1092 |
|
|
21
|
-
| `graphemer` | 1180 | 1086 |
|
|
22
|
-
| `grapheme-splitter` | 1175 | 1081 |
|
|
23
|
-
| `runes2` | 730 | 695 |
|
|
42
|
+
Expected output:
|
|
24
43
|
|
|
25
|
-
|
|
26
|
-
|
|
44
|
+
```text
|
|
45
|
+
15.1.0: Intl.Segmenter=1186 unicode-segmenter=1186 graphemer=1180 grapheme-splitter=1175 runes2=730
|
|
46
|
+
16.0.0: Intl.Segmenter=1092 unicode-segmenter=1092 graphemer=1086 grapheme-splitter=1081 runes2=695
|
|
47
|
+
```
|
|
27
48
|
|
|
28
49
|
## One caveat, and it is the only one
|
|
29
50
|
|
|
@@ -37,22 +58,29 @@ matrix:
|
|
|
37
58
|
| Node 20.x | 1186 | 1092 | split |
|
|
38
59
|
| Node 18.20.8 | 1187 | 1093 | not split |
|
|
39
60
|
|
|
40
|
-
Run
|
|
41
|
-
Node 18 the `Intl.Segmenter`
|
|
42
|
-
predates the deviation and passes every case. The other four
|
|
43
|
-
exact versions and hold identically on every Node.
|
|
61
|
+
Run the command above on Node 22 or 20 to get the expected output above. On
|
|
62
|
+
Node 18 the `Intl.Segmenter` value reads `1187` and `1093` instead: that ICU
|
|
63
|
+
predates the deviation and passes every case. The other four values are
|
|
64
|
+
pinned to exact library versions and hold identically on every Node.
|
|
44
65
|
|
|
45
66
|
The baseline was verified on Node 22.22.2 (ICU 78.2, Unicode 17.0).
|
|
46
67
|
|
|
47
|
-
##
|
|
68
|
+
## Reproducing SCOREBOARD.md and the rest of the gates
|
|
48
69
|
|
|
49
|
-
|
|
50
|
-
|
|
70
|
+
The committed `SCOREBOARD.md` (all four vendored Unicode versions, not just
|
|
71
|
+
the two above) is generated from this repository's own scripts, which are not
|
|
72
|
+
part of the published package, so reproducing it requires a checkout:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
git clone https://github.com/tamerkalla/grapheme-conformance.git && cd grapheme-conformance
|
|
76
|
+
npm ci
|
|
77
|
+
npm run scoreboard # regenerates SCOREBOARD.md and prints it
|
|
78
|
+
npm run scoreboard:check # asserts it is byte-identical to a fresh run
|
|
51
79
|
npm run typecheck
|
|
80
|
+
npm test # includes all ten integers above
|
|
52
81
|
npm run build
|
|
53
|
-
|
|
54
|
-
npm run scoreboard:check # asserts SCOREBOARD.md is byte-identical to a fresh run
|
|
82
|
+
node scripts/smoke.mjs # loads the ESM and CJS entry points
|
|
55
83
|
```
|
|
56
84
|
|
|
57
|
-
No network access is required by any of these. The vectors are committed
|
|
58
|
-
`vectors/` and are never fetched.
|
|
85
|
+
No network access is required by any of these. The vectors are committed
|
|
86
|
+
under `vectors/` and are never fetched.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grapheme-conformance",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Score any JavaScript grapheme segmenter against Unicode's official GraphemeBreakTest.txt. Find out which string splitters are wrong, and about what.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"unicode",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "tsup",
|
|
54
54
|
"typecheck": "tsc --noEmit",
|
|
55
|
+
"pretest": "npm run build",
|
|
55
56
|
"test": "vitest run",
|
|
56
57
|
"prescoreboard": "npm run build",
|
|
57
58
|
"scoreboard": "node scripts/scoreboard.mjs",
|
|
@@ -67,6 +68,7 @@
|
|
|
67
68
|
"tsup": "8.3.5",
|
|
68
69
|
"typescript": "5.7.2",
|
|
69
70
|
"unicode-segmenter": "0.17.3",
|
|
70
|
-
"vitest": "2.1.8"
|
|
71
|
+
"vitest": "2.1.8",
|
|
72
|
+
"yaml": "2.9.0"
|
|
71
73
|
}
|
|
72
74
|
}
|