Skip to content

Commit e82c9ef

Browse files
JLHwungmathiasbynens
authored andcommitted
Accumulate discontiguous ranges in legacy Unicode blocks
Retain all Specials records, including U+FEFF, while preserving the overlaps present in the historical source files. Assisted-By: GPT-6 Issue: #110
1 parent 458c85e commit e82c9ef

3 files changed

Lines changed: 45 additions & 5 deletions

File tree

‎scripts/parse-blocks-scripts-properties.mjs‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,8 @@ const parseBlocks = async (version) => {
305305
.split(';')
306306
.map((field) => field.trim());
307307
const canonicalBlockName = looseMatch('Block', blockName).value;
308-
map[canonicalBlockName] = regenerate().addRange(
309-
parseInt(start, 16),
310-
parseInt(end, 16),
311-
);
308+
map[canonicalBlockName] ??= regenerate();
309+
map[canonicalBlockName].addRange(parseInt(start, 16), parseInt(end, 16));
312310
}
313311
} else {
314312
map = await parseBlocksScriptsProperties('blocks', version);

‎tests/parser-formats.mjs‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,22 @@ test('Block names exclude inline comments in modern and legacy formats', async (
147147
}
148148
});
149149

150+
test('Repeated legacy block records accumulate without filling their gaps', async (t) => {
151+
t.mock.method(
152+
utils,
153+
'readDataFile',
154+
() => 'FEFF; FEFF; Specials\nFFF0; FFFD; Specials\n',
155+
);
156+
const blocks = await parseBlocks('3.0.1');
157+
t.assert.deepEqual(blocks.Specials.toArray(), [
158+
0xfeff,
159+
...Array.from({ length: 14 }, (_, i) => 0xfff0 + i),
160+
]);
161+
t.assert.ok(!blocks.No_Block.contains(0xfeff));
162+
t.assert.ok(!blocks.No_Block.contains(0xfffd));
163+
t.assert.ok(blocks.No_Block.contains(0xff00));
164+
});
165+
150166
test('Name aliases ignore inline comments without splitting alias groups', async (t) => {
151167
t.mock.method(
152168
utils,

‎tests/parsers.mjs‎

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ test('Historical titlecase digraphs retain their identity mapping', async (t) =>
2727
});
2828

2929
test('Block values cover Unicode, including No_Block gaps', async (t) => {
30-
for (const version of ['2.0.14', '3.1.0', '18.0.0']) {
30+
// Earlier files overlap Arabic Presentation Forms-B and Specials at U+FEFF.
31+
for (const version of ['2.1.9', '3.1.0', '18.0.0']) {
3132
const blocks = await parseBlocks(version);
3233
t.assert.ok(blocks.No_Block.contains(0x40000), version);
3334
t.assert.ok(!blocks.No_Block.contains(0x41), version);
@@ -50,6 +51,31 @@ test('Block values cover Unicode, including No_Block gaps', async (t) => {
5051
t.assert.equal(await parseBlocks('1.1.5'), undefined);
5152
});
5253

54+
test('Legacy blocks retain every discontiguous Specials range', async (t) => {
55+
for (const version of [
56+
'2.0.14',
57+
'2.1.2',
58+
'2.1.5',
59+
'2.1.8',
60+
'2.1.9',
61+
'3.0.0',
62+
'3.0.1',
63+
]) {
64+
const blocks = await parseBlocks(version);
65+
t.assert.ok(blocks.Specials.contains(0xfeff), version);
66+
t.assert.ok(blocks.Specials.contains(0xfff0), version);
67+
t.assert.ok(blocks.Specials.contains(0xfffd), version);
68+
t.assert.ok(!blocks.Specials.contains(0xff00), version);
69+
t.assert.ok(!blocks.No_Block.contains(0xfeff), version);
70+
// Preserve the overlap explicitly recorded by the earliest source files.
71+
t.assert.equal(
72+
blocks.Arabic_Presentation_Forms_B.contains(0xfeff),
73+
['2.0.14', '2.1.2', '2.1.5', '2.1.8'].includes(version),
74+
version,
75+
);
76+
}
77+
});
78+
5379
test('Hangul has pairwise canonical decomposition mappings', async (t) => {
5480
for (const version of ['2.0.14', '3.2.0', '18.0.0']) {
5581
const { Canonical } = await parseDecompositionMapping(version);

0 commit comments

Comments
 (0)