Something went wrong. Try again.
Pop-up dictionary browser extension for language learning. Successor to Yomichan. (PERSONAL FORK)
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151/* * Copyright (C) 2023-2025 Yomitan Authors * Copyright (C) 2020-2022 Yomichan Authors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */
import fs from 'fs';import path from 'path';import {performance} from 'perf_hooks';import {fileURLToPath} from 'url';import {getDictionaryArchiveEntries, getDictionaryArchiveJson, getIndexFileName, readArchiveEntryDataJson} from './dictionary-archive-util.js';import {parseJson} from './json.js';import {createJsonSchema} from './schema-validate.js';import {toError} from './to-error.js';
const dirname = path.dirname(fileURLToPath(import.meta.url));
/** * @param {string} relativeFileName * @returns {import('dev/dictionary-validate').Schema} */function readSchema(relativeFileName) { const fileName = path.join(dirname, relativeFileName); const source = fs.readFileSync(fileName, {encoding: 'utf8'}); return parseJson(source);}
/** * @param {import('dev/schema-validate').ValidateMode} mode * @param {import('@zip.js/zip.js').Entry[]} entries * @param {import('dev/dictionary-validate').SchemasDetails} schemasDetails */async function validateDictionaryBanks(mode, entries, schemasDetails) { for (const entry of entries) { const {filename} = entry; for (const [fileNameFormat, schema] of schemasDetails) { if (!fileNameFormat.test(filename)) { continue; }
let jsonSchema; try { jsonSchema = createJsonSchema(mode, schema); } catch (e) { const e2 = toError(e); e2.message += `\n(in file ${filename})`; throw e2; }
const data = await readArchiveEntryDataJson(entry);
try { jsonSchema.validate(data); } catch (e) { const e2 = toError(e); e2.message += `\n(in file ${filename})`; throw e2; } break; } }}
/** * Validates a dictionary from its zip archive. * @param {import('dev/schema-validate').ValidateMode} mode * @param {ArrayBuffer} archiveData * @param {import('dev/dictionary-validate').Schemas} schemas */export async function validateDictionary(mode, archiveData, schemas) { const entries = await getDictionaryArchiveEntries(archiveData); const indexFileName = getIndexFileName(); /** @type {import('dictionary-data').Index} */ const index = await getDictionaryArchiveJson(entries, indexFileName); const version = index.format || index.version;
try { const jsonSchema = createJsonSchema(mode, schemas.index); jsonSchema.validate(index); } catch (e) { const e2 = toError(e); e2.message += `\n(in file ${indexFileName})`; throw e2; }
/** @type {import('dev/dictionary-validate').SchemasDetails} */ const schemasDetails = [ [/^term_bank_(\d+)\.json$/, version === 1 ? schemas.termBankV1 : schemas.termBankV3], [/^term_meta_bank_(\d+)\.json$/, schemas.termMetaBankV3], [/^kanji_bank_(\d+)\.json$/, version === 1 ? schemas.kanjiBankV1 : schemas.kanjiBankV3], [/^kanji_meta_bank_(\d+)\.json$/, schemas.kanjiMetaBankV3], [/^tag_bank_(\d+)\.json$/, schemas.tagBankV3], ];
await validateDictionaryBanks(mode, entries, schemasDetails);}
/** * Returns a Schemas object from ext/data/schemas/*. * @returns {import('dev/dictionary-validate').Schemas} */export function getSchemas() { return { index: readSchema('../ext/data/schemas/dictionary-index-schema.json'), kanjiBankV1: readSchema('../ext/data/schemas/dictionary-kanji-bank-v1-schema.json'), kanjiBankV3: readSchema('../ext/data/schemas/dictionary-kanji-bank-v3-schema.json'), kanjiMetaBankV3: readSchema('../ext/data/schemas/dictionary-kanji-meta-bank-v3-schema.json'), tagBankV3: readSchema('../ext/data/schemas/dictionary-tag-bank-v3-schema.json'), termBankV1: readSchema('../ext/data/schemas/dictionary-term-bank-v1-schema.json'), termBankV3: readSchema('../ext/data/schemas/dictionary-term-bank-v3-schema.json'), termMetaBankV3: readSchema('../ext/data/schemas/dictionary-term-meta-bank-v3-schema.json'), };}
/** * Validates dictionary files and logs the results to the console. * @param {import('dev/schema-validate').ValidateMode} mode * @param {string[]} dictionaryFileNames */export async function testDictionaryFiles(mode, dictionaryFileNames) { const schemas = getSchemas();
for (const dictionaryFileName of dictionaryFileNames) { // eslint-disable-next-line no-restricted-syntax const start = performance.now(); try { console.log(`Validating ${dictionaryFileName}...`); const source = fs.readFileSync(dictionaryFileName); await validateDictionary(mode, source.buffer, schemas); // eslint-disable-next-line no-restricted-syntax const end = performance.now(); console.log(`No issues detected (${((end - start) / 1000).toFixed(2)}s)`); } catch (e) { // eslint-disable-next-line no-restricted-syntax const end = performance.now(); console.log(`Encountered an error (${((end - start) / 1000).toFixed(2)}s)`); console.warn(e); } }}