From ef79eab44bfd000792c610b968b5ceefd41e76a0 Mon Sep 17 00:00:00 2001 From: Darius Jahandarie Date: Sat, 4 Nov 2023 18:45:57 +0900 Subject: Modernize codebase - Use ES modules - Remove vendored libs and build them from npm using esbuild - Switch from JSZip to zip.js --- ext/js/language/deinflector.js | 2 +- ext/js/language/dictionary-database.js | 7 +- .../language/dictionary-importer-media-loader.js | 4 +- ext/js/language/dictionary-importer.js | 83 ++++++++++++---------- ext/js/language/dictionary-worker-handler.js | 11 ++- ext/js/language/dictionary-worker-main.js | 18 +---- ext/js/language/dictionary-worker-media-loader.js | 4 +- ext/js/language/dictionary-worker.js | 9 ++- ext/js/language/sandbox/dictionary-data-util.js | 2 +- ext/js/language/sandbox/japanese-util.js | 2 +- ext/js/language/text-scanner.js | 8 +-- ext/js/language/translator.js | 11 ++- 12 files changed, 79 insertions(+), 82 deletions(-) (limited to 'ext/js/language') diff --git a/ext/js/language/deinflector.js b/ext/js/language/deinflector.js index b11aa918..3012c29a 100644 --- a/ext/js/language/deinflector.js +++ b/ext/js/language/deinflector.js @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -class Deinflector { +export class Deinflector { constructor(reasons) { this.reasons = Deinflector.normalizeReasons(reasons); } diff --git a/ext/js/language/dictionary-database.js b/ext/js/language/dictionary-database.js index 9f2b9e45..da365da7 100644 --- a/ext/js/language/dictionary-database.js +++ b/ext/js/language/dictionary-database.js @@ -16,11 +16,10 @@ * along with this program. If not, see . */ -/* global - * Database - */ +import {log, stringReverse} from '../core.js'; +import {Database} from '../data/database.js'; -class DictionaryDatabase { +export class DictionaryDatabase { constructor() { this._db = new Database(); this._dbName = 'dict'; diff --git a/ext/js/language/dictionary-importer-media-loader.js b/ext/js/language/dictionary-importer-media-loader.js index 4024d0b3..7d4f798c 100644 --- a/ext/js/language/dictionary-importer-media-loader.js +++ b/ext/js/language/dictionary-importer-media-loader.js @@ -16,10 +16,12 @@ * along with this program. If not, see . */ +import {EventListenerCollection} from '../core.js'; + /** * Class used for loading and validating media during the dictionary import process. */ -class DictionaryImporterMediaLoader { +export class DictionaryImporterMediaLoader { /** * Attempts to load an image using an ArrayBuffer and a media type to return details about it. * @param {ArrayBuffer} content The binary content for the image, encoded as an ArrayBuffer. diff --git a/ext/js/language/dictionary-importer.js b/ext/js/language/dictionary-importer.js index 0cf3d5f5..bb5ac300 100644 --- a/ext/js/language/dictionary-importer.js +++ b/ext/js/language/dictionary-importer.js @@ -16,12 +16,11 @@ * along with this program. If not, see . */ -/* global - * JSZip - * MediaUtil - */ - -class DictionaryImporter { +import * as ajvSchemas from '../../lib/validate-schemas.js'; +import {BlobWriter, TextWriter, Uint8ArrayReader, ZipReader} from '../../lib/zip.js'; +import {stringReverse} from '../core.js'; +import {MediaUtil} from '../media/media-util.js'; +export class DictionaryImporter { constructor(mediaLoader, onProgress) { this._mediaLoader = mediaLoader; this._onProgress = typeof onProgress === 'function' ? onProgress : () => {}; @@ -39,18 +38,25 @@ class DictionaryImporter { this._progressReset(); // Read archive - const archive = await JSZip.loadAsync(archiveContent); - + const zipFileReader = new Uint8ArrayReader(new Uint8Array(archiveContent)); + const zipReader = new ZipReader(zipFileReader); + const zipEntries = await zipReader.getEntries(); + const zipEntriesObject = {}; + for (const entry of zipEntries) { + zipEntriesObject[entry.filename] = entry; + } // Read and validate index const indexFileName = 'index.json'; - const indexFile = archive.file(indexFileName); + const indexFile = zipEntriesObject[indexFileName]; if (!indexFile) { throw new Error('No dictionary index found in archive'); } - const index = JSON.parse(await indexFile.async('string')); + const indexContent = await indexFile.getData( + new TextWriter() + ); + const index = JSON.parse(indexContent); - const ajvSchemas = await import('/lib/validate-schemas.js'); if (!ajvSchemas.dictionaryIndex(index)) { throw this._formatAjvSchemaError(ajvSchemas.dictionaryIndex, indexFileName); } @@ -79,19 +85,19 @@ class DictionaryImporter { const dataBankSchemas = this._getDataBankSchemas(version); // Files - const termFiles = this._getArchiveFiles(archive, 'term_bank_?.json'); - const termMetaFiles = this._getArchiveFiles(archive, 'term_meta_bank_?.json'); - const kanjiFiles = this._getArchiveFiles(archive, 'kanji_bank_?.json'); - const kanjiMetaFiles = this._getArchiveFiles(archive, 'kanji_meta_bank_?.json'); - const tagFiles = this._getArchiveFiles(archive, 'tag_bank_?.json'); + const termFiles = this._getArchiveFiles(zipEntriesObject, 'term_bank_?.json'); + const termMetaFiles = this._getArchiveFiles(zipEntriesObject, 'term_meta_bank_?.json'); + const kanjiFiles = this._getArchiveFiles(zipEntriesObject, 'kanji_bank_?.json'); + const kanjiMetaFiles = this._getArchiveFiles(zipEntriesObject, 'kanji_meta_bank_?.json'); + const tagFiles = this._getArchiveFiles(zipEntriesObject, 'tag_bank_?.json'); // Load data this._progressNextStep(termFiles.length + termMetaFiles.length + kanjiFiles.length + kanjiMetaFiles.length + tagFiles.length); - const termList = await this._readFileSequence(ajvSchemas, termFiles, convertTermBankEntry, dataBankSchemas[0], dictionaryTitle); - const termMetaList = await this._readFileSequence(ajvSchemas, termMetaFiles, convertTermMetaBankEntry, dataBankSchemas[1], dictionaryTitle); - const kanjiList = await this._readFileSequence(ajvSchemas, kanjiFiles, convertKanjiBankEntry, dataBankSchemas[2], dictionaryTitle); - const kanjiMetaList = await this._readFileSequence(ajvSchemas, kanjiMetaFiles, convertKanjiMetaBankEntry, dataBankSchemas[3], dictionaryTitle); - const tagList = await this._readFileSequence(ajvSchemas, tagFiles, convertTagBankEntry, dataBankSchemas[4], dictionaryTitle); + const termList = await this._readFileSequence(termFiles, convertTermBankEntry, dataBankSchemas[0], dictionaryTitle); + const termMetaList = await this._readFileSequence(termMetaFiles, convertTermMetaBankEntry, dataBankSchemas[1], dictionaryTitle); + const kanjiList = await this._readFileSequence(kanjiFiles, convertKanjiBankEntry, dataBankSchemas[2], dictionaryTitle); + const kanjiMetaList = await this._readFileSequence(kanjiMetaFiles, convertKanjiMetaBankEntry, dataBankSchemas[3], dictionaryTitle); + const tagList = await this._readFileSequence(tagFiles, convertTagBankEntry, dataBankSchemas[4], dictionaryTitle); this._addOldIndexTags(index, tagList, dictionaryTitle); // Prefix wildcard support @@ -124,7 +130,7 @@ class DictionaryImporter { // Async requirements this._progressNextStep(requirements.length); - const {media} = await this._resolveAsyncRequirements(requirements, archive); + const {media} = await this._resolveAsyncRequirements(requirements, zipEntriesObject); // Add dictionary descriptor this._progressNextStep(termList.length + termMetaList.length + kanjiList.length + kanjiMetaList.length + tagList.length + media.length); @@ -294,9 +300,9 @@ class DictionaryImporter { return target; } - async _resolveAsyncRequirements(requirements, archive) { + async _resolveAsyncRequirements(requirements, zipEntriesObject) { const media = new Map(); - const context = {archive, media}; + const context = {zipEntriesObject, media}; for (const requirement of requirements) { await this._resolveAsyncRequirement(context, requirement); @@ -386,13 +392,16 @@ class DictionaryImporter { } // Find file in archive - const file = context.archive.file(path); + const file = context.zipEntriesObject[path]; if (file === null) { throw createError('Could not find image'); } // Load file content - let content = await file.async('arraybuffer'); + let content = await (await file.getData( + new BlobWriter() + )).arrayBuffer(); + const mediaType = MediaUtil.getImageMediaTypeFromFileName(path); if (mediaType === null) { throw createError('Could not determine media type for image'); @@ -484,33 +493,35 @@ class DictionaryImporter { } } - _getArchiveFiles(archive, fileNameFormat) { + _getArchiveFiles(zipEntriesObject, fileNameFormat) { const indexPosition = fileNameFormat.indexOf('?'); const prefix = fileNameFormat.substring(0, indexPosition); const suffix = fileNameFormat.substring(indexPosition + 1); const results = []; - for (let i = 1; true; ++i) { - const fileName = `${prefix}${i}${suffix}`; - const file = archive.file(fileName); - if (!file) { break; } - results.push(file); + for (const f of Object.keys(zipEntriesObject)) { + if (f.startsWith(prefix) && f.endsWith(suffix)) { + results.push(zipEntriesObject[f]); + } } return results; } - async _readFileSequence(ajvSchemas, files, convertEntry, schemaName, dictionaryTitle) { + async _readFileSequence(files, convertEntry, schemaName, dictionaryTitle) { const progressData = this._progressData; let startIndex = 0; const results = []; - for (const file of files) { - const entries = JSON.parse(await file.async('string')); + for (const fileName of Object.keys(files)) { + const content = await files[fileName].getData( + new TextWriter() + ); + const entries = JSON.parse(content); startIndex = progressData.index; this._progress(); if (!ajvSchemas[schemaName](entries)) { - throw this._formatAjvSchemaError(ajvSchemas[schemaName], file.name); + throw this._formatAjvSchemaError(ajvSchemas[schemaName], fileName); } progressData.index = startIndex + 1; diff --git a/ext/js/language/dictionary-worker-handler.js b/ext/js/language/dictionary-worker-handler.js index 0e3e8495..b8c41b26 100644 --- a/ext/js/language/dictionary-worker-handler.js +++ b/ext/js/language/dictionary-worker-handler.js @@ -16,13 +16,12 @@ * along with this program. If not, see . */ -/* global - * DictionaryDatabase - * DictionaryImporter - * DictionaryWorkerMediaLoader - */ +import {serializeError} from '../core.js'; +import {DictionaryDatabase} from './dictionary-database.js'; +import {DictionaryImporter} from './dictionary-importer.js'; +import {DictionaryWorkerMediaLoader} from './dictionary-worker-media-loader.js'; -class DictionaryWorkerHandler { +export class DictionaryWorkerHandler { constructor() { this._mediaLoader = new DictionaryWorkerMediaLoader(); } diff --git a/ext/js/language/dictionary-worker-main.js b/ext/js/language/dictionary-worker-main.js index cbb3247c..6d2386aa 100644 --- a/ext/js/language/dictionary-worker-main.js +++ b/ext/js/language/dictionary-worker-main.js @@ -16,22 +16,8 @@ * along with this program. If not, see . */ -/* global - * DictionaryWorkerHandler - */ - -self.importScripts( - '/lib/jszip.min.js', - '/js/core.js', - '/js/data/database.js', - '/js/data/json-schema.js', - '/js/general/cache-map.js', - '/js/language/dictionary-database.js', - '/js/language/dictionary-importer.js', - '/js/language/dictionary-worker-handler.js', - '/js/language/dictionary-worker-media-loader.js', - '/js/media/media-util.js' -); +import {log} from '../core.js'; +import {DictionaryWorkerHandler} from './dictionary-worker-handler.js'; (() => { try { diff --git a/ext/js/language/dictionary-worker-media-loader.js b/ext/js/language/dictionary-worker-media-loader.js index d2ef4fae..d58e46c5 100644 --- a/ext/js/language/dictionary-worker-media-loader.js +++ b/ext/js/language/dictionary-worker-media-loader.js @@ -16,11 +16,13 @@ * along with this program. If not, see . */ +import {deserializeError, generateId} from '../core.js'; + /** * Class used for loading and validating media from a worker thread * during the dictionary import process. */ -class DictionaryWorkerMediaLoader { +export class DictionaryWorkerMediaLoader { /** * Creates a new instance of the media loader. */ diff --git a/ext/js/language/dictionary-worker.js b/ext/js/language/dictionary-worker.js index b415a346..18c300af 100644 --- a/ext/js/language/dictionary-worker.js +++ b/ext/js/language/dictionary-worker.js @@ -16,11 +16,10 @@ * along with this program. If not, see . */ -/* global - * DictionaryImporterMediaLoader - */ +import {deserializeError, serializeError} from '../core.js'; +import {DictionaryImporterMediaLoader} from './dictionary-importer-media-loader.js'; -class DictionaryWorker { +export class DictionaryWorker { constructor() { this._dictionaryImporterMediaLoader = new DictionaryImporterMediaLoader(); } @@ -47,7 +46,7 @@ class DictionaryWorker { _invoke(action, params, transfer, onProgress, formatResult) { return new Promise((resolve, reject) => { - const worker = new Worker('/js/language/dictionary-worker-main.js', {}); + const worker = new Worker('/js/language/dictionary-worker-main.js', {type: 'module'}); const details = { complete: false, worker, diff --git a/ext/js/language/sandbox/dictionary-data-util.js b/ext/js/language/sandbox/dictionary-data-util.js index 323076e8..1b71346a 100644 --- a/ext/js/language/sandbox/dictionary-data-util.js +++ b/ext/js/language/sandbox/dictionary-data-util.js @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -class DictionaryDataUtil { +export class DictionaryDataUtil { static groupTermTags(dictionaryEntry) { const {headwords} = dictionaryEntry; const headwordCount = headwords.length; diff --git a/ext/js/language/sandbox/japanese-util.js b/ext/js/language/sandbox/japanese-util.js index eee70f9c..316b1c2e 100644 --- a/ext/js/language/sandbox/japanese-util.js +++ b/ext/js/language/sandbox/japanese-util.js @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -const JapaneseUtil = (() => { +export const JapaneseUtil = (() => { const HIRAGANA_SMALL_TSU_CODE_POINT = 0x3063; const KATAKANA_SMALL_TSU_CODE_POINT = 0x30c3; const KATAKANA_SMALL_KA_CODE_POINT = 0x30f5; diff --git a/ext/js/language/text-scanner.js b/ext/js/language/text-scanner.js index af5cc8fe..bd5b0fbe 100644 --- a/ext/js/language/text-scanner.js +++ b/ext/js/language/text-scanner.js @@ -16,11 +16,11 @@ * along with this program. If not, see . */ -/* global - * DocumentUtil - */ +import {EventDispatcher, EventListenerCollection, clone, isObject, log, promiseTimeout} from '../core.js'; +import {DocumentUtil} from '../dom/document-util.js'; +import {yomichan} from '../yomichan.js'; -class TextScanner extends EventDispatcher { +export class TextScanner extends EventDispatcher { constructor({ node, getSearchContext, diff --git a/ext/js/language/translator.js b/ext/js/language/translator.js index 3b47cc51..4044f379 100644 --- a/ext/js/language/translator.js +++ b/ext/js/language/translator.js @@ -16,16 +16,15 @@ * along with this program. If not, see . */ -/* global - * Deinflector - * RegexUtil - * TextSourceMap - */ +import {RegexUtil} from '../general/regex-util.js'; +import {TextSourceMap} from '../general/text-source-map.js'; +import {Deinflector} from './deinflector.js'; +import {DictionaryDatabase} from './dictionary-database.js'; /** * Class which finds term and kanji dictionary entries for text. */ -class Translator { +export class Translator { /** * Information about how popup content should be shown, specifically related to the outer popup frame. * @typedef {object} TermFrequency -- cgit v1.2.3