🤭

JSCのUCDを更新するスクリプト

2024/09/17に公開

正規表現のプロパティエスケープなどの実装のために、JavaScriptエンジンはUCD(=Unicode Character Database)に関する情報を知っている必要がある。

WebKitのJSエンジンであるJavaScriptCoreではUCDを ./Source/JavaScriptCore/ucd 配下にファイルとしてそのまま配置している。

Unicodeのバージョンが上がるとtest262の方に更新が入るので、それに追従する形でJSエンジンのUCDのバージョンを上げる必要がある。

前回 15.1 に上げたときはすべて手動でやったが、手動でやるのは面倒くさいのでスクリプトを書いた。

#!/usr/bin/env node

const fs = require('fs');
const path = require('path');

const version = '16.0.0';
const versionWithoutPatch = '16.0';

const files = [
    { name: 'CaseFolding.txt', url: `https://unicode.org/Public/${version}/ucd/CaseFolding.txt` },
    { name: 'DerivedBinaryProperties.txt', url: `https://unicode.org/Public/${version}/ucd/extracted/DerivedBinaryProperties.txt` },
    { name: 'DerivedCoreProperties.txt', url: `https://unicode.org/Public/${version}/ucd/DerivedCoreProperties.txt` },
    { name: 'DerivedNormalizationProps.txt', url: `https://unicode.org/Public/${version}/ucd/DerivedNormalizationProps.txt` },
    { name: 'emoji-data.txt', url: `https://unicode.org/Public/${version}/ucd/emoji/emoji-data.txt` },
    { name: 'emoji-sequences.txt', url: `https://unicode.org/Public/emoji/${versionWithoutPatch}/emoji-sequences.txt` },
    { name: 'emoji-zwj-sequences.txt', url: `https://unicode.org/Public/emoji/${versionWithoutPatch}/emoji-zwj-sequences.txt` },
    { name: 'PropertyAliases.txt', url: `https://unicode.org/Public/${version}/ucd/PropertyAliases.txt` },
    { name: 'PropertyValueAliases.txt', url: `https://unicode.org/Public/${version}/ucd/PropertyValueAliases.txt` },
    { name: 'PropList.txt', url: `https://unicode.org/Public/${version}/ucd/PropList.txt` },
    { name: 'ScriptExtensions.txt', url: `https://unicode.org/Public/${version}/ucd/ScriptExtensions.txt` },
    { name: 'Scripts.txt', url: `https://unicode.org/Public/${version}/ucd/Scripts.txt` },
    { name: 'UnicodeData.txt', url: `https://unicode.org/Public/${version}/ucd/UnicodeData.txt` }
];

const targetDir = path.join(process.cwd(), 'Source', 'JavaScriptCore', 'ucd');

if (!fs.existsSync(targetDir)) {
    fs.mkdirSync(targetDir, { recursive: true });
}

async function downloadFile(file) {
    const filePath = path.join(targetDir, file.name);
    
    try {
        console.log(`Downloading ${file.name}...`);
        const response = await fetch(file.url);

        if (!response.ok) {
            throw new Error(`Failed to download ${file.name}: ${response.statusText}`);
        }

        const fileStream = fs.createWriteStream(filePath);
        const reader = response.body.getReader();
        let done = false;

        while (!done) {
            const { value, done: readerDone } = await reader.read();
            if (value) {
                fileStream.write(value);
            }
            done = readerDone;
        }

        fileStream.close();
        console.log(`${file.name} has been downloaded`);
    } catch (error) {
        console.error(`Error downloading ${file.name}: ${error.message}`);
    }
}

(async () => {
    await Promise.all(files.map(downloadFile));
})();

Discussion