@chr33s/pdf-unicode-trie 5.0.0

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.
@@ -0,0 +1,258 @@
1
+ import { describe, expect, test } from "vitest";
2
+
3
+ import UnicodeTrieBuilder from "../src/builder.js";
4
+ import UnicodeTrie from "../src/index.js";
5
+
6
+ describe("unicode trie", () => {
7
+ test("set", () => {
8
+ const trie = new UnicodeTrieBuilder(10, 666);
9
+ trie.set(0x4567, 99);
10
+ expect(trie.get(0x4566)).toBe(10);
11
+ expect(trie.get(0x4567)).toBe(99);
12
+ expect(trie.get(-1)).toBe(666);
13
+ expect(trie.get(0x110000)).toBe(666);
14
+ });
15
+
16
+ test("set -> compacted trie", () => {
17
+ const builder = new UnicodeTrieBuilder(10, 666);
18
+ builder.set(0x4567, 99);
19
+
20
+ const trie = builder.freeze();
21
+ expect(trie.get(0x4566)).toBe(10);
22
+ expect(trie.get(0x4567)).toBe(99);
23
+ expect(trie.get(-1)).toBe(666);
24
+ expect(trie.get(0x110000)).toBe(666);
25
+ });
26
+
27
+ test("setRange", () => {
28
+ const trie = new UnicodeTrieBuilder(10, 666);
29
+ trie.setRange(13, 6666, 7788, false);
30
+ trie.setRange(6000, 7000, 9900, true);
31
+
32
+ expect(trie.get(12)).toBe(10);
33
+ expect(trie.get(13)).toBe(7788);
34
+ expect(trie.get(5999)).toBe(7788);
35
+ expect(trie.get(6000)).toBe(9900);
36
+ expect(trie.get(7000)).toBe(9900);
37
+ expect(trie.get(7001)).toBe(10);
38
+ expect(trie.get(0x110000)).toBe(666);
39
+ });
40
+
41
+ test("setRange -> compacted trie", () => {
42
+ const builder = new UnicodeTrieBuilder(10, 666);
43
+ builder.setRange(13, 6666, 7788, false);
44
+ builder.setRange(6000, 7000, 9900, true);
45
+
46
+ const trie = builder.freeze();
47
+ expect(trie.get(12)).toBe(10);
48
+ expect(trie.get(13)).toBe(7788);
49
+ expect(trie.get(5999)).toBe(7788);
50
+ expect(trie.get(6000)).toBe(9900);
51
+ expect(trie.get(7000)).toBe(9900);
52
+ expect(trie.get(7001)).toBe(10);
53
+ expect(trie.get(0x110000)).toBe(666);
54
+ });
55
+
56
+ test("toBuffer produces valid compressed output", async () => {
57
+ const builder = new UnicodeTrieBuilder();
58
+ builder.set(0x4567, 99);
59
+
60
+ const buf = await builder.toBuffer();
61
+ // Verify buffer has correct header format
62
+ expect(buf.length).toBeGreaterThan(12);
63
+ // Verify high start and error values in header
64
+ expect(buf.readUInt32LE(0)).toBe(builder.freeze().highStart);
65
+ expect(buf.readUInt32LE(4)).toBe(builder.freeze().errorValue);
66
+ // Verify that the output can be loaded back as a valid trie
67
+ const trie = await UnicodeTrie.create(buf);
68
+ expect(trie.get(0x4567)).toBe(99);
69
+ expect(trie.get(0x4566)).toBe(0);
70
+ });
71
+
72
+ test("should work with compressed serialization format", async () => {
73
+ const builder = new UnicodeTrieBuilder(10, 666);
74
+ builder.setRange(13, 6666, 7788, false);
75
+ builder.setRange(6000, 7000, 9900, true);
76
+
77
+ const buf = await builder.toBuffer();
78
+ const trie = await UnicodeTrie.create(buf);
79
+ expect(trie.get(12)).toBe(10);
80
+ expect(trie.get(13)).toBe(7788);
81
+ expect(trie.get(5999)).toBe(7788);
82
+ expect(trie.get(6000)).toBe(9900);
83
+ expect(trie.get(7000)).toBe(9900);
84
+ expect(trie.get(7001)).toBe(10);
85
+ expect(trie.get(0x110000)).toBe(666);
86
+ });
87
+
88
+ const rangeTests = [
89
+ {
90
+ ranges: [
91
+ [0, 0, 0, 0],
92
+ [0, 0x40, 0, 0],
93
+ [0x40, 0xe7, 0x1234, 0],
94
+ [0xe7, 0x3400, 0, 0],
95
+ [0x3400, 0x9fa6, 0x6162, 0],
96
+ [0x9fa6, 0xda9e, 0x3132, 0],
97
+ [0xdada, 0xeeee, 0x87ff, 0],
98
+ [0xeeee, 0x11111, 1, 0],
99
+ [0x11111, 0x44444, 0x6162, 0],
100
+ [0x44444, 0x60003, 0, 0],
101
+ [0xf0003, 0xf0004, 0xf, 0],
102
+ [0xf0004, 0xf0006, 0x10, 0],
103
+ [0xf0006, 0xf0007, 0x11, 0],
104
+ [0xf0007, 0xf0040, 0x12, 0],
105
+ [0xf0040, 0x110000, 0, 0],
106
+ ],
107
+ check: [
108
+ [0, 0],
109
+ [0x40, 0],
110
+ [0xe7, 0x1234],
111
+ [0x3400, 0],
112
+ [0x9fa6, 0x6162],
113
+ [0xda9e, 0x3132],
114
+ [0xdada, 0],
115
+ [0xeeee, 0x87ff],
116
+ [0x11111, 1],
117
+ [0x44444, 0x6162],
118
+ [0xf0003, 0],
119
+ [0xf0004, 0xf],
120
+ [0xf0006, 0x10],
121
+ [0xf0007, 0x11],
122
+ [0xf0040, 0x12],
123
+ [0x110000, 0],
124
+ ],
125
+ },
126
+ {
127
+ ranges: [
128
+ [0, 0, 0, 0],
129
+ [0x21, 0x7f, 0x5555, 1],
130
+ [0x2f800, 0x2fedc, 0x7a, 1],
131
+ [0x72, 0xdd, 3, 1],
132
+ [0xdd, 0xde, 4, 0],
133
+ [0x201, 0x240, 6, 1],
134
+ [0x241, 0x280, 6, 1],
135
+ [0x281, 0x2c0, 6, 1],
136
+ [0x2f987, 0x2fa98, 5, 1],
137
+ [0x2f777, 0x2f883, 0, 1],
138
+ [0x2f900, 0x2ffaa, 1, 0],
139
+ [0x2ffaa, 0x2ffab, 2, 1],
140
+ [0x2ffbb, 0x2ffc0, 7, 1],
141
+ ],
142
+ check: [
143
+ [0, 0],
144
+ [0x21, 0],
145
+ [0x72, 0x5555],
146
+ [0xdd, 3],
147
+ [0xde, 4],
148
+ [0x201, 0],
149
+ [0x240, 6],
150
+ [0x241, 0],
151
+ [0x280, 6],
152
+ [0x281, 0],
153
+ [0x2c0, 6],
154
+ [0x2f883, 0],
155
+ [0x2f987, 0x7a],
156
+ [0x2fa98, 5],
157
+ [0x2fedc, 0x7a],
158
+ [0x2ffaa, 1],
159
+ [0x2ffab, 2],
160
+ [0x2ffbb, 0],
161
+ [0x2ffc0, 7],
162
+ [0x110000, 0],
163
+ ],
164
+ },
165
+ {
166
+ ranges: [
167
+ [0, 0, 9, 0],
168
+ [0x31, 0xa4, 1, 0],
169
+ [0x3400, 0x6789, 2, 0],
170
+ [0x8000, 0x89ab, 9, 1],
171
+ [0x9000, 0xa000, 4, 1],
172
+ [0xabcd, 0xbcde, 3, 1],
173
+ [0x55555, 0x110000, 6, 1],
174
+ [0xcccc, 0x55555, 6, 1],
175
+ ],
176
+ check: [
177
+ [0, 9],
178
+ [0x31, 9],
179
+ [0xa4, 1],
180
+ [0x3400, 9],
181
+ [0x6789, 2],
182
+ [0x9000, 9],
183
+ [0xa000, 4],
184
+ [0xabcd, 9],
185
+ [0xbcde, 3],
186
+ [0xcccc, 9],
187
+ [0x110000, 6],
188
+ ],
189
+ },
190
+ {
191
+ ranges: [[0, 0, 3, 0]],
192
+ check: [
193
+ [0, 3],
194
+ [0x110000, 3],
195
+ ],
196
+ },
197
+ {
198
+ ranges: [
199
+ [0, 0, 3, 0],
200
+ [0, 0x110000, 5, 1],
201
+ ],
202
+ check: [
203
+ [0, 3],
204
+ [0x110000, 5],
205
+ ],
206
+ },
207
+ ] as const;
208
+
209
+ type TrieLike = { get: (codePoint: number) => number };
210
+
211
+ const findMismatch = (trie: TrieLike, checks: readonly (readonly [number, number])[]) => {
212
+ let start = 0;
213
+ for (const [end, expected] of checks) {
214
+ for (let codePoint = start; codePoint < end; codePoint++) {
215
+ const actual = trie.get(codePoint);
216
+ if (actual !== expected) {
217
+ return { codePoint, expected, actual } as const;
218
+ }
219
+ }
220
+ start = end;
221
+ }
222
+ return null;
223
+ };
224
+
225
+ test("should pass range tests", () => {
226
+ for (const rangeTest of rangeTests) {
227
+ let initialValue = 0;
228
+ let errorValue = 0x0bad;
229
+ let index = 0;
230
+
231
+ if (rangeTest.ranges[index][1] < 0) {
232
+ errorValue = rangeTest.ranges[index][2];
233
+ index++;
234
+ }
235
+
236
+ initialValue = rangeTest.ranges[index++][2];
237
+ const builder = new UnicodeTrieBuilder(initialValue, errorValue);
238
+
239
+ for (const range of rangeTest.ranges.slice(index)) {
240
+ builder.setRange(range[0], range[1] - 1, range[2], range[3] !== 0);
241
+ }
242
+
243
+ const frozen = builder.freeze();
244
+
245
+ const builderMismatch = findMismatch(builder, rangeTest.check);
246
+ const builderMessage = builderMismatch
247
+ ? `builder mismatch at U+${builderMismatch.codePoint.toString(16)}: expected ${builderMismatch.expected}, got ${builderMismatch.actual}`
248
+ : undefined;
249
+ expect(builderMismatch, builderMessage).toBeNull();
250
+
251
+ const frozenMismatch = findMismatch(frozen, rangeTest.check);
252
+ const frozenMessage = frozenMismatch
253
+ ? `frozen mismatch at U+${frozenMismatch.codePoint.toString(16)}: expected ${frozenMismatch.expected}, got ${frozenMismatch.actual}`
254
+ : undefined;
255
+ expect(frozenMismatch, frozenMessage).toBeNull();
256
+ }
257
+ });
258
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist"
6
+ },
7
+ "include": ["src/**/*.ts"],
8
+ "exclude": ["dist", "test", "scripts", "node_modules"]
9
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "noEmit": true,
5
+ "rootDir": "."
6
+ },
7
+ "include": [
8
+ "**/*.ts",
9
+ ],
10
+ "exclude": [
11
+ "dist",
12
+ "node_modules"
13
+ ]
14
+ }
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ environment: "node",
6
+ include: ["test/**/*.test.ts"],
7
+ },
8
+ });