From 2446520309e1b4b517da540e724eb795ee4be1c2 Mon Sep 17 00:00:00 2001 From: stephenmk Date: Wed, 8 Jan 2025 17:01:35 -0600 Subject: [PATCH 1/5] Add `minimumYomitanVersion` parameter to dictionary index schema --- ext/data/schemas/dictionary-index-schema.json | 4 ++++ ext/js/dictionary/dictionary-importer.js | 12 +++++++++++- types/ext/dictionary-data.d.ts | 1 + types/ext/dictionary-importer.d.ts | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/ext/data/schemas/dictionary-index-schema.json b/ext/data/schemas/dictionary-index-schema.json index ec8b73b20d..f68e321e11 100644 --- a/ext/data/schemas/dictionary-index-schema.json +++ b/ext/data/schemas/dictionary-index-schema.json @@ -23,6 +23,10 @@ "type": "string", "description": "Revision of the dictionary. This value is displayed, and used to check for dictionary updates." }, + "minimumYomitanVersion": { + "type": "string", + "description": "Minimum version of Yomitan that is compatible with this dictionary." + }, "sequenced": { "type": "boolean", "default": false, diff --git a/ext/js/dictionary/dictionary-importer.js b/ext/js/dictionary/dictionary-importer.js index e8a72ba821..021046410f 100644 --- a/ext/js/dictionary/dictionary-importer.js +++ b/ext/js/dictionary/dictionary-importer.js @@ -24,6 +24,7 @@ import { ZipReader as ZipReader0, configure, } from '../../lib/zip.js'; +import {compareRevisions} from 'dictionary-data-util.js'; import {ExtensionError} from '../core/extension-error.js'; import {parseJson} from '../core/json.js'; import {toError} from '../core/to-error.js'; @@ -328,7 +329,16 @@ export class DictionaryImporter { styles, }; - const {author, url, description, attribution, frequencyMode, isUpdatable, sourceLanguage, targetLanguage} = index; + const {minimumYomitanVersion, author, url, description, attribution, frequencyMode, isUpdatable, sourceLanguage, targetLanguage} = index; + if (typeof minimumYomitanVersion === 'string') { + const {version} = chrome.runtime.getManifest(); + if (version === "0.0.0.0") { + // Running a development version of Yomitan + } else if (compareRevisions(version, minimumYomitanVersion)) { + throw new Error(`Dictionary is incompatible with this version of Yomitan (${version}; minimum required: ${minimumYomitanVersion})`); + } + summary.minimumYomitanVersion = minimumYomitanVersion; + } if (typeof author === 'string') { summary.author = author; } if (typeof url === 'string') { summary.url = url; } if (typeof description === 'string') { summary.description = description; } diff --git a/types/ext/dictionary-data.d.ts b/types/ext/dictionary-data.d.ts index 92e52b8d61..1b1d7c3306 100644 --- a/types/ext/dictionary-data.d.ts +++ b/types/ext/dictionary-data.d.ts @@ -24,6 +24,7 @@ export type Index = { version?: IndexVersion; title: string; revision: string; + minimumYomitanVersion?: string; sequenced?: boolean; isUpdatable?: true; indexUrl?: string; diff --git a/types/ext/dictionary-importer.d.ts b/types/ext/dictionary-importer.d.ts index 97472e6cfa..5f42b8f684 100644 --- a/types/ext/dictionary-importer.d.ts +++ b/types/ext/dictionary-importer.d.ts @@ -46,6 +46,7 @@ export type Summary = { title: string; revision: string; sequenced: boolean; + minimumYomitanVersion?: string; version: number; importDate: number; prefixWildcardsSupported: boolean; From 12eaf86af80d18d69f07e89053431c8c71fb8c08 Mon Sep 17 00:00:00 2001 From: stephenmk Date: Wed, 8 Jan 2025 18:47:13 -0600 Subject: [PATCH 2/5] Can't use `chrome.runtime` in `DictionaryImporter` class --- ext/js/dictionary/dictionary-importer.js | 12 ++++++------ .../pages/settings/dictionary-import-controller.js | 1 + types/ext/dictionary-importer.d.ts | 2 ++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/ext/js/dictionary/dictionary-importer.js b/ext/js/dictionary/dictionary-importer.js index 021046410f..599993d55a 100644 --- a/ext/js/dictionary/dictionary-importer.js +++ b/ext/js/dictionary/dictionary-importer.js @@ -24,7 +24,7 @@ import { ZipReader as ZipReader0, configure, } from '../../lib/zip.js'; -import {compareRevisions} from 'dictionary-data-util.js'; +import {compareRevisions} from './dictionary-data-util.js'; import {ExtensionError} from '../core/extension-error.js'; import {parseJson} from '../core/json.js'; import {toError} from '../core/to-error.js'; @@ -181,8 +181,9 @@ export class DictionaryImporter { } } + const yomitanVersion = details.yomitanVersion; /** @type {import('dictionary-importer').SummaryDetails} */ - const summaryDetails = {prefixWildcardsSupported, counts, styles}; + const summaryDetails = {prefixWildcardsSupported, counts, styles, yomitanVersion}; const summary = this._createSummary(dictionaryTitle, version, index, summaryDetails); await dictionaryDatabase.bulkAdd('dictionaries', [summary], 0, 1); @@ -331,11 +332,10 @@ export class DictionaryImporter { const {minimumYomitanVersion, author, url, description, attribution, frequencyMode, isUpdatable, sourceLanguage, targetLanguage} = index; if (typeof minimumYomitanVersion === 'string') { - const {version} = chrome.runtime.getManifest(); - if (version === "0.0.0.0") { + if (details.yomitanVersion === "0.0.0.0") { // Running a development version of Yomitan - } else if (compareRevisions(version, minimumYomitanVersion)) { - throw new Error(`Dictionary is incompatible with this version of Yomitan (${version}; minimum required: ${minimumYomitanVersion})`); + } else if (compareRevisions(details.yomitanVersion, minimumYomitanVersion)) { + throw new Error(`Dictionary is incompatible with this version of Yomitan (${details.yomitanVersion}; minimum required: ${minimumYomitanVersion})`); } summary.minimumYomitanVersion = minimumYomitanVersion; } diff --git a/ext/js/pages/settings/dictionary-import-controller.js b/ext/js/pages/settings/dictionary-import-controller.js index d8e803f019..48fedbbc4f 100644 --- a/ext/js/pages/settings/dictionary-import-controller.js +++ b/ext/js/pages/settings/dictionary-import-controller.js @@ -555,6 +555,7 @@ export class DictionaryImportController { const optionsFull = await this._settingsController.getOptionsFull(); const importDetails = { prefixWildcardsSupported: optionsFull.global.database.prefixWildcardsSupported, + yomitanVersion: chrome.runtime.getManifest().version, }; for (let i = 0; i < importProgressTracker.dictionaryCount; ++i) { diff --git a/types/ext/dictionary-importer.d.ts b/types/ext/dictionary-importer.d.ts index 5f42b8f684..27b177cf9c 100644 --- a/types/ext/dictionary-importer.d.ts +++ b/types/ext/dictionary-importer.d.ts @@ -40,6 +40,7 @@ export type ImportResult = { export type ImportDetails = { prefixWildcardsSupported: boolean; + yomitanVersion: string; }; export type Summary = { @@ -68,6 +69,7 @@ export type SummaryDetails = { prefixWildcardsSupported: boolean; counts: SummaryCounts; styles: string; + yomitanVersion: string; }; export type SummaryCounts = { From 17345292c6ea036c4d53b6aaab4dd1d42197fd77 Mon Sep 17 00:00:00 2001 From: stephenmk Date: Wed, 8 Jan 2025 19:24:00 -0600 Subject: [PATCH 3/5] Add `yomitanVersion` parameter to test data --- test/fixtures/translator-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/translator-test.js b/test/fixtures/translator-test.js index 857e8a98ae..3a6efb6f10 100644 --- a/test/fixtures/translator-test.js +++ b/test/fixtures/translator-test.js @@ -49,7 +49,7 @@ export async function createTranslatorContext(dictionaryDirectory, dictionaryNam const {errors, result} = await dictionaryImporter.importDictionary( dictionaryDatabase, testDictionaryData, - {prefixWildcardsSupported: true}, + {prefixWildcardsSupported: true, yomitanVersion: "0.0.0.0"}, ); expect(errors.length).toEqual(0); From 94f564fb30b01e1e59f6b4197a7ab006d5e1a42f Mon Sep 17 00:00:00 2001 From: stephenmk Date: Wed, 8 Jan 2025 19:28:18 -0600 Subject: [PATCH 4/5] More test data adjustments --- test/database.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/database.test.js b/test/database.test.js index 50fc213449..27e62ba5d2 100644 --- a/test/database.test.js +++ b/test/database.test.js @@ -122,7 +122,7 @@ describe('Database', () => { // Setup database const dictionaryDatabase = new DictionaryDatabase(); /** @type {import('dictionary-importer').ImportDetails} */ - const defaultImportDetails = {prefixWildcardsSupported: false}; + const defaultImportDetails = {prefixWildcardsSupported: false, yomitanVersion: "0.0.0.0"}; // Database not open await expect.soft(dictionaryDatabase.deleteDictionary(title, 1000, () => {})).rejects.toThrow('Database not open'); @@ -167,7 +167,7 @@ describe('Database', () => { const testDictionarySource = await createTestDictionaryArchiveData(name); /** @type {import('dictionary-importer').ImportDetails} */ - const detaultImportDetails = {prefixWildcardsSupported: false}; + const detaultImportDetails = {prefixWildcardsSupported: false, yomitanVersion: "0.0.0.0"}; await expect.soft(createDictionaryImporter(expect).importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Dictionary has invalid data'); await dictionaryDatabase.close(); }); @@ -199,7 +199,7 @@ describe('Database', () => { const {result: importDictionaryResult, errors: importDictionaryErrors} = await dictionaryImporter.importDictionary( dictionaryDatabase, testDictionarySource, - {prefixWildcardsSupported: true}, + {prefixWildcardsSupported: true, yomitanVersion: "0.0.0.0"}, ); if (importDictionaryResult) { @@ -324,7 +324,7 @@ describe('Database', () => { // Import data const dictionaryImporter = createDictionaryImporter(expect); - await dictionaryImporter.importDictionary(dictionaryDatabase, testDictionarySource, {prefixWildcardsSupported: true}); + await dictionaryImporter.importDictionary(dictionaryDatabase, testDictionarySource, {prefixWildcardsSupported: true, yomitanVersion: "0.0.0.0"}); // Clear switch (clearMethod) { From 9867070f4c76010f5d0601c36754458d85a1caf8 Mon Sep 17 00:00:00 2001 From: stephenmk Date: Wed, 8 Jan 2025 19:35:25 -0600 Subject: [PATCH 5/5] Use single quotes to please the tests --- ext/js/dictionary/dictionary-importer.js | 2 +- test/database.test.js | 8 ++++---- test/fixtures/translator-test.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/js/dictionary/dictionary-importer.js b/ext/js/dictionary/dictionary-importer.js index 599993d55a..f0586f3302 100644 --- a/ext/js/dictionary/dictionary-importer.js +++ b/ext/js/dictionary/dictionary-importer.js @@ -332,7 +332,7 @@ export class DictionaryImporter { const {minimumYomitanVersion, author, url, description, attribution, frequencyMode, isUpdatable, sourceLanguage, targetLanguage} = index; if (typeof minimumYomitanVersion === 'string') { - if (details.yomitanVersion === "0.0.0.0") { + if (details.yomitanVersion === '0.0.0.0') { // Running a development version of Yomitan } else if (compareRevisions(details.yomitanVersion, minimumYomitanVersion)) { throw new Error(`Dictionary is incompatible with this version of Yomitan (${details.yomitanVersion}; minimum required: ${minimumYomitanVersion})`); diff --git a/test/database.test.js b/test/database.test.js index 27e62ba5d2..1edbf53abf 100644 --- a/test/database.test.js +++ b/test/database.test.js @@ -122,7 +122,7 @@ describe('Database', () => { // Setup database const dictionaryDatabase = new DictionaryDatabase(); /** @type {import('dictionary-importer').ImportDetails} */ - const defaultImportDetails = {prefixWildcardsSupported: false, yomitanVersion: "0.0.0.0"}; + const defaultImportDetails = {prefixWildcardsSupported: false, yomitanVersion: '0.0.0.0'}; // Database not open await expect.soft(dictionaryDatabase.deleteDictionary(title, 1000, () => {})).rejects.toThrow('Database not open'); @@ -167,7 +167,7 @@ describe('Database', () => { const testDictionarySource = await createTestDictionaryArchiveData(name); /** @type {import('dictionary-importer').ImportDetails} */ - const detaultImportDetails = {prefixWildcardsSupported: false, yomitanVersion: "0.0.0.0"}; + const detaultImportDetails = {prefixWildcardsSupported: false, yomitanVersion: '0.0.0.0'}; await expect.soft(createDictionaryImporter(expect).importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Dictionary has invalid data'); await dictionaryDatabase.close(); }); @@ -199,7 +199,7 @@ describe('Database', () => { const {result: importDictionaryResult, errors: importDictionaryErrors} = await dictionaryImporter.importDictionary( dictionaryDatabase, testDictionarySource, - {prefixWildcardsSupported: true, yomitanVersion: "0.0.0.0"}, + {prefixWildcardsSupported: true, yomitanVersion: '0.0.0.0'}, ); if (importDictionaryResult) { @@ -324,7 +324,7 @@ describe('Database', () => { // Import data const dictionaryImporter = createDictionaryImporter(expect); - await dictionaryImporter.importDictionary(dictionaryDatabase, testDictionarySource, {prefixWildcardsSupported: true, yomitanVersion: "0.0.0.0"}); + await dictionaryImporter.importDictionary(dictionaryDatabase, testDictionarySource, {prefixWildcardsSupported: true, yomitanVersion: '0.0.0.0'}); // Clear switch (clearMethod) { diff --git a/test/fixtures/translator-test.js b/test/fixtures/translator-test.js index 3a6efb6f10..4b82598770 100644 --- a/test/fixtures/translator-test.js +++ b/test/fixtures/translator-test.js @@ -49,7 +49,7 @@ export async function createTranslatorContext(dictionaryDirectory, dictionaryNam const {errors, result} = await dictionaryImporter.importDictionary( dictionaryDatabase, testDictionaryData, - {prefixWildcardsSupported: true, yomitanVersion: "0.0.0.0"}, + {prefixWildcardsSupported: true, yomitanVersion: '0.0.0.0'}, ); expect(errors.length).toEqual(0);