/*
* Copyright (C) 2023-2024 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 .
*/
// eslint-disable-next-line no-template-curly-in-string
const placeholder = '${title}';
/**
* @template {import('test/translator').OptionsType} T
* @param {T} type
* @param {import('test/translator').OptionsPresetObject} optionsPresets
* @param {import('test/translator').OptionsList} optionsArray
* @returns {import('test/translator').OptionsPresetGeneric}
* @throws {Error}
*/
function getCompositePreset(type, optionsPresets, optionsArray) {
const preset = /** @type {import('test/translator').OptionsPresetGeneric} */ ({type});
if (!Array.isArray(optionsArray)) { optionsArray = [optionsArray]; }
for (const entry of optionsArray) {
switch (typeof entry) {
case 'string':
{
if (!Object.prototype.hasOwnProperty.call(optionsPresets, entry)) {
throw new Error('Options preset not found');
}
const preset2 = optionsPresets[entry];
if (preset2.type !== type) {
throw new Error('Invalid options preset type');
}
Object.assign(preset, structuredClone(preset2));
}
break;
case 'object':
if (entry.type !== type) {
throw new Error('Invalid options preset type');
}
Object.assign(preset, structuredClone(entry));
break;
default:
throw new Error('Invalid options type');
}
}
return preset;
}
/**
* @param {string} dictionaryName
* @param {import('test/translator').OptionsPresetObject} optionsPresets
* @param {import('test/translator').OptionsList} optionsArray
* @returns {import('translation').FindKanjiOptions}
*/
export function createFindKanjiOptions(dictionaryName, optionsPresets, optionsArray) {
const preset = getCompositePreset('kanji', optionsPresets, optionsArray);
/** @type {import('translation').KanjiEnabledDictionaryMap} */
const enabledDictionaryMap = new Map();
const presetEnabledDictionaryMap = preset.enabledDictionaryMap;
if (Array.isArray(presetEnabledDictionaryMap)) {
for (const [key, value] of presetEnabledDictionaryMap) {
enabledDictionaryMap.set(key === placeholder ? dictionaryName : key, value);
}
}
return {
enabledDictionaryMap,
removeNonJapaneseCharacters: !!preset.removeNonJapaneseCharacters
};
}
/**
* @param {string} dictionaryName
* @param {import('test/translator').OptionsPresetObject} optionsPresets
* @param {import('test/translator').OptionsList} optionsArray
* @returns {import('translation').FindTermsOptions}
*/
export function createFindTermsOptions(dictionaryName, optionsPresets, optionsArray) {
const preset = getCompositePreset('terms', optionsPresets, optionsArray);
/** @type {import('translation').TermEnabledDictionaryMap} */
const enabledDictionaryMap = new Map();
const presetEnabledDictionaryMap = preset.enabledDictionaryMap;
if (Array.isArray(presetEnabledDictionaryMap)) {
for (const [key, value] of presetEnabledDictionaryMap) {
enabledDictionaryMap.set(key === placeholder ? dictionaryName : key, value);
}
}
/** @type {import('translation').FindTermsTextReplacements} */
const textReplacements = [];
if (Array.isArray(preset.textReplacements)) {
for (const value of preset.textReplacements) {
if (Array.isArray(value)) {
const array = [];
for (const {pattern, flags, replacement} of value) {
array.push({pattern: new RegExp(pattern, flags), replacement});
}
textReplacements.push(array);
} else {
// Null
textReplacements.push(value);
}
}
}
const {
matchType,
deinflect,
mainDictionary,
sortFrequencyDictionary,
sortFrequencyDictionaryOrder,
removeNonJapaneseCharacters,
convertHalfWidthCharacters,
convertNumericCharacters,
convertAlphabeticCharacters,
convertHiraganaToKatakana,
convertKatakanaToHiragana,
collapseEmphaticSequences,
excludeDictionaryDefinitions,
searchResolution
} = preset;
return {
matchType: typeof matchType !== 'undefined' ? matchType : 'exact',
deinflect: typeof deinflect !== 'undefined' ? deinflect : true,
mainDictionary: typeof mainDictionary !== 'undefined' && mainDictionary !== placeholder ? mainDictionary : dictionaryName,
sortFrequencyDictionary: typeof sortFrequencyDictionary !== 'undefined' ? sortFrequencyDictionary : null,
sortFrequencyDictionaryOrder: typeof sortFrequencyDictionaryOrder !== 'undefined' ? sortFrequencyDictionaryOrder : 'ascending',
removeNonJapaneseCharacters: typeof removeNonJapaneseCharacters !== 'undefined' ? removeNonJapaneseCharacters : false,
convertHalfWidthCharacters: typeof convertHalfWidthCharacters !== 'undefined' ? convertHalfWidthCharacters : 'false',
convertNumericCharacters: typeof convertNumericCharacters !== 'undefined' ? convertNumericCharacters : 'false',
convertAlphabeticCharacters: typeof convertAlphabeticCharacters !== 'undefined' ? convertAlphabeticCharacters : 'false',
convertHiraganaToKatakana: typeof convertHiraganaToKatakana !== 'undefined' ? convertHiraganaToKatakana : 'false',
convertKatakanaToHiragana: typeof convertKatakanaToHiragana !== 'undefined' ? convertKatakanaToHiragana : 'false',
collapseEmphaticSequences: typeof collapseEmphaticSequences !== 'undefined' ? collapseEmphaticSequences : 'false',
textReplacements,
enabledDictionaryMap,
excludeDictionaryDefinitions: Array.isArray(excludeDictionaryDefinitions) ? new Set(excludeDictionaryDefinitions) : null,
searchResolution: typeof searchResolution !== 'undefined' ? searchResolution : 'letter'
};
}