aboutsummaryrefslogtreecommitdiff
path: root/ext/js/data/sandbox
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2024-03-04 07:43:31 -0500
committerGitHub <noreply@github.com>2024-03-04 12:43:31 +0000
commit4fe881d68d4c1182bee2e78a559c2064aaf48b0d (patch)
tree00e8b209b90cae66ca289f5ea3e0c466e17d6fd3 /ext/js/data/sandbox
parent81fc2bd6d063db92f90171722e8129875bdb56cd (diff)
Move sandbox files (#731)
* Move sandbox files * Update order
Diffstat (limited to 'ext/js/data/sandbox')
-rw-r--r--ext/js/data/sandbox/anki-note-data-creator.js936
-rw-r--r--ext/js/data/sandbox/array-buffer-util.js72
-rw-r--r--ext/js/data/sandbox/string-util.js70
3 files changed, 0 insertions, 1078 deletions
diff --git a/ext/js/data/sandbox/anki-note-data-creator.js b/ext/js/data/sandbox/anki-note-data-creator.js
deleted file mode 100644
index d0456b0f..00000000
--- a/ext/js/data/sandbox/anki-note-data-creator.js
+++ /dev/null
@@ -1,936 +0,0 @@
-/*
- * Copyright (C) 2023-2024 Yomitan Authors
- * Copyright (C) 2021-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 {getDisambiguations, getGroupedPronunciations, getPronunciationsOfType, getTermFrequency, groupTermTags} from '../../dictionary/dictionary-data-util.js';
-import {distributeFurigana, distributeFuriganaInflected} from '../../language/ja/japanese.js';
-
-/**
- * Creates a compatibility representation of the specified data.
- * @param {string} marker The marker that is being used for template rendering.
- * @param {import('anki-templates-internal').CreateDetails} details Information which is used to generate the data.
- * @returns {import('anki-templates').NoteData} An object used for rendering Anki templates.
- */
-export function createAnkiNoteData(marker, {
- dictionaryEntry,
- resultOutputMode,
- mode,
- glossaryLayoutMode,
- compactTags,
- context,
- media
-}) {
- const definition = createCachedValue(getDefinition.bind(null, dictionaryEntry, context, resultOutputMode));
- const uniqueExpressions = createCachedValue(getUniqueExpressions.bind(null, dictionaryEntry));
- const uniqueReadings = createCachedValue(getUniqueReadings.bind(null, dictionaryEntry));
- const context2 = createCachedValue(getPublicContext.bind(null, context));
- const pitches = createCachedValue(getPitches.bind(null, dictionaryEntry));
- const pitchCount = createCachedValue(getPitchCount.bind(null, pitches));
- const phoneticTranscriptions = createCachedValue(getPhoneticTranscriptions.bind(null, dictionaryEntry));
-
- if (typeof media !== 'object' || media === null || Array.isArray(media)) {
- media = {
- audio: void 0,
- screenshot: void 0,
- clipboardImage: void 0,
- clipboardText: void 0,
- selectionText: void 0,
- textFurigana: [],
- dictionaryMedia: {}
- };
- }
- /** @type {import('anki-templates').NoteData} */
- const result = {
- marker,
- get definition() { return getCachedValue(definition); },
- glossaryLayoutMode,
- compactTags,
- group: (resultOutputMode === 'group'),
- merge: (resultOutputMode === 'merge'),
- modeTermKanji: (mode === 'term-kanji'),
- modeTermKana: (mode === 'term-kana'),
- modeKanji: (mode === 'kanji'),
- compactGlossaries: (glossaryLayoutMode === 'compact'),
- get uniqueExpressions() { return getCachedValue(uniqueExpressions); },
- get uniqueReadings() { return getCachedValue(uniqueReadings); },
- get pitches() { return getCachedValue(pitches); },
- get pitchCount() { return getCachedValue(pitchCount); },
- get phoneticTranscriptions() { return getCachedValue(phoneticTranscriptions); },
- get context() { return getCachedValue(context2); },
- media,
- dictionaryEntry
- };
- Object.defineProperty(result, 'dictionaryEntry', {
- configurable: false,
- enumerable: false,
- writable: false,
- value: dictionaryEntry
- });
- return result;
-}
-
-/**
- * Creates a deferred-evaluation value.
- * @template [T=unknown]
- * @param {() => T} getter The function to invoke to get the return value.
- * @returns {import('anki-templates-internal').CachedValue<T>} An object which can be passed into `getCachedValue`.
- */
-export function createCachedValue(getter) {
- return {getter, hasValue: false, value: void 0};
-}
-
-/**
- * Gets the value of a cached object.
- * @template [T=unknown]
- * @param {import('anki-templates-internal').CachedValue<T>} item An object that was returned from `createCachedValue`.
- * @returns {T} The result of evaluating the getter, which is cached after the first invocation.
- */
-export function getCachedValue(item) {
- if (item.hasValue) { return /** @type {T} */ (item.value); }
- const value = item.getter();
- item.value = value;
- item.hasValue = true;
- return value;
-}
-
-// Private
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @returns {?import('dictionary').TermSource}
- */
-function getPrimarySource(dictionaryEntry) {
- for (const headword of dictionaryEntry.headwords) {
- for (const source of headword.sources) {
- if (source.isPrimary) { return source; }
- }
- }
- return null;
-}
-
-/**
- * @param {import('dictionary').DictionaryEntry} dictionaryEntry
- * @returns {string[]}
- */
-function getUniqueExpressions(dictionaryEntry) {
- if (dictionaryEntry.type === 'term') {
- const results = new Set();
- for (const {term} of dictionaryEntry.headwords) {
- results.add(term);
- }
- return [...results];
- } else {
- return [];
- }
-}
-
-/**
- * @param {import('dictionary').DictionaryEntry} dictionaryEntry
- * @returns {string[]}
- */
-function getUniqueReadings(dictionaryEntry) {
- if (dictionaryEntry.type === 'term') {
- const results = new Set();
- for (const {reading} of dictionaryEntry.headwords) {
- results.add(reading);
- }
- return [...results];
- } else {
- return [];
- }
-}
-
-/**
- * @param {import('anki-templates-internal').Context} context
- * @returns {import('anki-templates').Context}
- */
-function getPublicContext(context) {
- let {documentTitle, query, fullQuery} = context;
- if (typeof documentTitle !== 'string') { documentTitle = ''; }
- return {
- query,
- fullQuery,
- document: {
- title: documentTitle
- }
- };
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry|import('dictionary').KanjiDictionaryEntry} dictionaryEntry
- * @returns {number[]}
- */
-function getFrequencyNumbers(dictionaryEntry) {
- let previousDictionary;
- const frequencies = [];
- for (const {dictionary, frequency, displayValue} of dictionaryEntry.frequencies) {
- if (dictionary === previousDictionary) {
- continue;
- }
- previousDictionary = dictionary;
-
- if (displayValue !== null) {
- const frequencyMatch = displayValue.match(/\d+/);
- if (frequencyMatch !== null) {
- frequencies.push(Number.parseInt(frequencyMatch[0], 10));
- continue;
- }
- }
- frequencies.push(frequency);
- }
- return frequencies;
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry|import('dictionary').KanjiDictionaryEntry} dictionaryEntry
- * @returns {number}
- */
-function getFrequencyHarmonic(dictionaryEntry) {
- const frequencies = getFrequencyNumbers(dictionaryEntry);
-
- if (frequencies.length === 0) {
- return -1;
- }
-
- let total = 0;
- for (const frequency of frequencies) {
- total += 1 / frequency;
- }
- return Math.floor(frequencies.length / total);
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry|import('dictionary').KanjiDictionaryEntry} dictionaryEntry
- * @returns {number}
- */
-function getFrequencyAverage(dictionaryEntry) {
- const frequencies = getFrequencyNumbers(dictionaryEntry);
-
- if (frequencies.length === 0) {
- return -1;
- }
-
- let total = 0;
- for (const frequency of frequencies) {
- total += frequency;
- }
- return Math.floor(total / frequencies.length);
-}
-
-/**
- * @param {import('dictionary').DictionaryEntry} dictionaryEntry
- * @returns {import('anki-templates').PitchGroup[]}
- */
-function getPitches(dictionaryEntry) {
- /** @type {import('anki-templates').PitchGroup[]} */
- const results = [];
- if (dictionaryEntry.type === 'term') {
- for (const {dictionary, pronunciations} of getGroupedPronunciations(dictionaryEntry)) {
- /** @type {import('anki-templates').Pitch[]} */
- const pitches = [];
- for (const groupedPronunciation of pronunciations) {
- const {pronunciation} = groupedPronunciation;
- if (pronunciation.type !== 'pitch-accent') { continue; }
- const {position, nasalPositions, devoicePositions, tags} = pronunciation;
- const {terms, reading, exclusiveTerms, exclusiveReadings} = groupedPronunciation;
- pitches.push({
- expressions: terms,
- reading,
- position,
- nasalPositions,
- devoicePositions,
- tags: convertPitchTags(tags),
- exclusiveExpressions: exclusiveTerms,
- exclusiveReadings
- });
- }
- results.push({dictionary, pitches});
- }
- }
- return results;
-}
-
-/**
- * @param {import('dictionary').DictionaryEntry} dictionaryEntry
- * @returns {import('anki-templates').TranscriptionGroup[]}
- */
-function getPhoneticTranscriptions(dictionaryEntry) {
- const results = [];
- if (dictionaryEntry.type === 'term') {
- for (const {dictionary, pronunciations} of getGroupedPronunciations(dictionaryEntry)) {
- const phoneticTranscriptions = [];
- for (const groupedPronunciation of pronunciations) {
- const {pronunciation} = groupedPronunciation;
- if (pronunciation.type !== 'phonetic-transcription') { continue; }
- const {ipa, tags} = pronunciation;
- const {terms, reading, exclusiveTerms, exclusiveReadings} = groupedPronunciation;
- phoneticTranscriptions.push({
- expressions: terms,
- reading,
- ipa,
- tags,
- exclusiveExpressions: exclusiveTerms,
- exclusiveReadings
- });
- }
- results.push({dictionary, phoneticTranscriptions});
- }
- }
- return results;
-}
-
-/**
- * @param {import('anki-templates-internal').CachedValue<import('anki-templates').PitchGroup[]>} cachedPitches
- * @returns {number}
- */
-function getPitchCount(cachedPitches) {
- const pitches = getCachedValue(cachedPitches);
- return pitches.reduce((i, v) => i + v.pitches.length, 0);
-}
-
-/**
- * @param {import('dictionary').DictionaryEntry} dictionaryEntry
- * @param {import('anki-templates-internal').Context} context
- * @param {import('settings').ResultOutputMode} resultOutputMode
- * @returns {import('anki-templates').DictionaryEntry}
- */
-function getDefinition(dictionaryEntry, context, resultOutputMode) {
- switch (dictionaryEntry.type) {
- case 'term':
- return getTermDefinition(dictionaryEntry, context, resultOutputMode);
- case 'kanji':
- return getKanjiDefinition(dictionaryEntry, context);
- default:
- return /** @type {import('anki-templates').UnknownDictionaryEntry} */ ({});
- }
-}
-
-/**
- * @param {import('dictionary').KanjiDictionaryEntry} dictionaryEntry
- * @param {import('anki-templates-internal').Context} context
- * @returns {import('anki-templates').KanjiDictionaryEntry}
- */
-function getKanjiDefinition(dictionaryEntry, context) {
- const {character, dictionary, onyomi, kunyomi, definitions} = dictionaryEntry;
-
- let {url} = context;
- if (typeof url !== 'string') { url = ''; }
-
- const stats = createCachedValue(getKanjiStats.bind(null, dictionaryEntry));
- const tags = createCachedValue(convertTags.bind(null, dictionaryEntry.tags));
- const frequencies = createCachedValue(getKanjiFrequencies.bind(null, dictionaryEntry));
- const frequencyHarmonic = createCachedValue(getFrequencyHarmonic.bind(null, dictionaryEntry));
- const frequencyAverage = createCachedValue(getFrequencyAverage.bind(null, dictionaryEntry));
- const cloze = createCachedValue(getCloze.bind(null, dictionaryEntry, context));
-
- return {
- type: 'kanji',
- character,
- dictionary,
- onyomi,
- kunyomi,
- glossary: definitions,
- get tags() { return getCachedValue(tags); },
- get stats() { return getCachedValue(stats); },
- get frequencies() { return getCachedValue(frequencies); },
- get frequencyHarmonic() { return getCachedValue(frequencyHarmonic); },
- get frequencyAverage() { return getCachedValue(frequencyAverage); },
- url,
- get cloze() { return getCachedValue(cloze); }
- };
-}
-
-/**
- * @param {import('dictionary').KanjiDictionaryEntry} dictionaryEntry
- * @returns {import('anki-templates').KanjiStatGroups}
- */
-function getKanjiStats(dictionaryEntry) {
- /** @type {import('anki-templates').KanjiStatGroups} */
- const results = {};
- for (const [key, value] of Object.entries(dictionaryEntry.stats)) {
- results[key] = value.map(convertKanjiStat);
- }
- return results;
-}
-
-/**
- * @param {import('dictionary').KanjiStat} kanjiStat
- * @returns {import('anki-templates').KanjiStat}
- */
-function convertKanjiStat({name, category, content, order, score, dictionary, value}) {
- return {
- name,
- category,
- notes: content,
- order,
- score,
- dictionary,
- value
- };
-}
-
-/**
- * @param {import('dictionary').KanjiDictionaryEntry} dictionaryEntry
- * @returns {import('anki-templates').KanjiFrequency[]}
- */
-function getKanjiFrequencies(dictionaryEntry) {
- /** @type {import('anki-templates').KanjiFrequency[]} */
- const results = [];
- for (const {index, dictionary, dictionaryIndex, dictionaryPriority, character, frequency, displayValue} of dictionaryEntry.frequencies) {
- results.push({
- index,
- dictionary,
- dictionaryOrder: {
- index: dictionaryIndex,
- priority: dictionaryPriority
- },
- character,
- frequency: displayValue !== null ? displayValue : frequency
- });
- }
- return results;
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @param {import('anki-templates-internal').Context} context
- * @param {import('settings').ResultOutputMode} resultOutputMode
- * @returns {import('anki-templates').TermDictionaryEntry}
- */
-function getTermDefinition(dictionaryEntry, context, resultOutputMode) {
- /** @type {import('anki-templates').TermDictionaryEntryType} */
- let type = 'term';
- switch (resultOutputMode) {
- case 'group': type = 'termGrouped'; break;
- case 'merge': type = 'termMerged'; break;
- }
-
- const {inflectionRuleChainCandidates, score, dictionaryIndex, dictionaryPriority, sourceTermExactMatchCount, definitions} = dictionaryEntry;
-
- let {url} = context;
- if (typeof url !== 'string') { url = ''; }
-
- const primarySource = getPrimarySource(dictionaryEntry);
-
- const dictionaryNames = createCachedValue(getTermDictionaryNames.bind(null, dictionaryEntry));
- const commonInfo = createCachedValue(getTermDictionaryEntryCommonInfo.bind(null, dictionaryEntry, type));
- const termTags = createCachedValue(getTermTags.bind(null, dictionaryEntry, type));
- const expressions = createCachedValue(getTermExpressions.bind(null, dictionaryEntry));
- const frequencies = createCachedValue(getTermFrequencies.bind(null, dictionaryEntry));
- const frequencyHarmonic = createCachedValue(getFrequencyHarmonic.bind(null, dictionaryEntry));
- const frequencyAverage = createCachedValue(getFrequencyAverage.bind(null, dictionaryEntry));
- const pitches = createCachedValue(getTermPitches.bind(null, dictionaryEntry));
- const phoneticTranscriptions = createCachedValue(getTermPhoneticTranscriptions.bind(null, dictionaryEntry));
- const glossary = createCachedValue(getTermGlossaryArray.bind(null, dictionaryEntry, type));
- const cloze = createCachedValue(getCloze.bind(null, dictionaryEntry, context));
- const furiganaSegments = createCachedValue(getTermFuriganaSegments.bind(null, dictionaryEntry, type));
- const sequence = createCachedValue(getTermDictionaryEntrySequence.bind(null, dictionaryEntry));
-
- return {
- type,
- id: (type === 'term' && definitions.length > 0 ? definitions[0].id : void 0),
- source: (primarySource !== null ? primarySource.transformedText : null),
- rawSource: (primarySource !== null ? primarySource.originalText : null),
- sourceTerm: (type !== 'termMerged' ? (primarySource !== null ? primarySource.deinflectedText : null) : void 0),
- inflectionRuleChainCandidates,
- score,
- isPrimary: (type === 'term' ? dictionaryEntry.isPrimary : void 0),
- get sequence() { return getCachedValue(sequence); },
- get dictionary() { return getCachedValue(dictionaryNames)[0]; },
- dictionaryOrder: {
- index: dictionaryIndex,
- priority: dictionaryPriority
- },
- get dictionaryNames() { return getCachedValue(dictionaryNames); },
- get expression() {
- const {uniqueTerms} = getCachedValue(commonInfo);
- return (type === 'term' || type === 'termGrouped' ? uniqueTerms[0] : uniqueTerms);
- },
- get reading() {
- const {uniqueReadings} = getCachedValue(commonInfo);
- return (type === 'term' || type === 'termGrouped' ? uniqueReadings[0] : uniqueReadings);
- },
- get expressions() { return getCachedValue(expressions); },
- get glossary() { return getCachedValue(glossary); },
- get definitionTags() { return type === 'term' ? getCachedValue(commonInfo).definitionTags : void 0; },
- get termTags() { return getCachedValue(termTags); },
- get definitions() { return getCachedValue(commonInfo).definitions; },
- get frequencies() { return getCachedValue(frequencies); },
- get frequencyHarmonic() { return getCachedValue(frequencyHarmonic); },
- get frequencyAverage() { return getCachedValue(frequencyAverage); },
- get pitches() { return getCachedValue(pitches); },
- get phoneticTranscriptions() { return getCachedValue(phoneticTranscriptions); },
- sourceTermExactMatchCount,
- url,
- get cloze() { return getCachedValue(cloze); },
- get furiganaSegments() { return getCachedValue(furiganaSegments); }
- };
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @returns {string[]}
- */
-function getTermDictionaryNames(dictionaryEntry) {
- const dictionaryNames = new Set();
- for (const {dictionary} of dictionaryEntry.definitions) {
- dictionaryNames.add(dictionary);
- }
- return [...dictionaryNames];
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @param {import('anki-templates').TermDictionaryEntryType} type
- * @returns {import('anki-templates').TermDictionaryEntryCommonInfo}
- */
-function getTermDictionaryEntryCommonInfo(dictionaryEntry, type) {
- const merged = (type === 'termMerged');
- const hasDefinitions = (type !== 'term');
-
- /** @type {Set<string>} */
- const allTermsSet = new Set();
- /** @type {Set<string>} */
- const allReadingsSet = new Set();
- for (const {term, reading} of dictionaryEntry.headwords) {
- allTermsSet.add(term);
- allReadingsSet.add(reading);
- }
- const uniqueTerms = [...allTermsSet];
- const uniqueReadings = [...allReadingsSet];
-
- /** @type {import('anki-templates').TermDefinition[]} */
- const definitions = [];
- /** @type {import('anki-templates').Tag[]} */
- const definitionTags = [];
- for (const {tags, headwordIndices, entries, dictionary, sequences} of dictionaryEntry.definitions) {
- const definitionTags2 = [];
- for (const tag of tags) {
- definitionTags.push(convertTag(tag));
- definitionTags2.push(convertTag(tag));
- }
- if (!hasDefinitions) { continue; }
- const only = merged ? getDisambiguations(dictionaryEntry.headwords, headwordIndices, allTermsSet, allReadingsSet) : void 0;
- definitions.push({
- sequence: sequences[0],
- dictionary,
- glossary: entries,
- definitionTags: definitionTags2,
- only
- });
- }
-
- return {
- uniqueTerms,
- uniqueReadings,
- definitionTags,
- definitions: hasDefinitions ? definitions : void 0
- };
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @returns {import('anki-templates').TermFrequency[]}
- */
-function getTermFrequencies(dictionaryEntry) {
- const results = [];
- const {headwords} = dictionaryEntry;
- for (const {headwordIndex, dictionary, dictionaryIndex, dictionaryPriority, hasReading, frequency, displayValue} of dictionaryEntry.frequencies) {
- const {term, reading} = headwords[headwordIndex];
- results.push({
- index: results.length,
- expressionIndex: headwordIndex,
- dictionary,
- dictionaryOrder: {
- index: dictionaryIndex,
- priority: dictionaryPriority
- },
- expression: term,
- reading,
- hasReading,
- frequency: displayValue !== null ? displayValue : frequency
- });
- }
- return results;
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @returns {import('anki-templates').TermPitchAccent[]}
- */
-function getTermPitches(dictionaryEntry) {
- const results = [];
- const {headwords} = dictionaryEntry;
- for (const {headwordIndex, dictionary, dictionaryIndex, dictionaryPriority, pronunciations} of dictionaryEntry.pronunciations) {
- const {term, reading} = headwords[headwordIndex];
- const pitches = getPronunciationsOfType(pronunciations, 'pitch-accent');
- const cachedPitches = createCachedValue(getTermPitchesInner.bind(null, pitches));
- results.push({
- index: results.length,
- expressionIndex: headwordIndex,
- dictionary,
- dictionaryOrder: {
- index: dictionaryIndex,
- priority: dictionaryPriority
- },
- expression: term,
- reading,
- get pitches() { return getCachedValue(cachedPitches); }
- });
- }
- return results;
-}
-
-/**
- * @param {import('dictionary').PitchAccent[]} pitches
- * @returns {import('anki-templates').PitchAccent[]}
- */
-function getTermPitchesInner(pitches) {
- const results = [];
- for (const {position, tags} of pitches) {
- const cachedTags = createCachedValue(convertTags.bind(null, tags));
- results.push({
- position,
- get tags() { return getCachedValue(cachedTags); }
- });
- }
- return results;
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @returns {import('anki-templates').TermPhoneticTranscription[]}
- */
-function getTermPhoneticTranscriptions(dictionaryEntry) {
- const results = [];
- const {headwords} = dictionaryEntry;
- for (const {headwordIndex, dictionary, dictionaryIndex, dictionaryPriority, pronunciations} of dictionaryEntry.pronunciations) {
- const {term, reading} = headwords[headwordIndex];
- const phoneticTranscriptions = getPronunciationsOfType(pronunciations, 'phonetic-transcription');
- const termPhoneticTranscriptions = getTermPhoneticTranscriptionsInner(phoneticTranscriptions);
- results.push({
- index: results.length,
- expressionIndex: headwordIndex,
- dictionary,
- dictionaryOrder: {
- index: dictionaryIndex,
- priority: dictionaryPriority
- },
- expression: term,
- reading,
- get phoneticTranscriptions() { return termPhoneticTranscriptions; }
- });
- }
-
- return results;
-}
-
-/**
- * @param {import('dictionary').PhoneticTranscription[]} phoneticTranscriptions
- * @returns {import('anki-templates').PhoneticTranscription[]}
- */
-function getTermPhoneticTranscriptionsInner(phoneticTranscriptions) {
- const results = [];
- for (const {ipa, tags} of phoneticTranscriptions) {
- const cachedTags = createCachedValue(convertTags.bind(null, tags));
- results.push({
- ipa,
- get tags() { return getCachedValue(cachedTags); }
- });
- }
- return results;
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @returns {import('anki-templates').TermHeadword[]}
- */
-function getTermExpressions(dictionaryEntry) {
- const results = [];
- const {headwords} = dictionaryEntry;
- for (let i = 0, ii = headwords.length; i < ii; ++i) {
- const {term, reading, tags, sources: [{deinflectedText}], wordClasses} = headwords[i];
- const termTags = createCachedValue(convertTags.bind(null, tags));
- const frequencies = createCachedValue(getTermExpressionFrequencies.bind(null, dictionaryEntry, i));
- const pitches = createCachedValue(getTermExpressionPitches.bind(null, dictionaryEntry, i));
- const termFrequency = createCachedValue(getTermExpressionTermFrequency.bind(null, termTags));
- const furiganaSegments = createCachedValue(getTermHeadwordFuriganaSegments.bind(null, term, reading));
- const item = {
- sourceTerm: deinflectedText,
- expression: term,
- reading,
- get termTags() { return getCachedValue(termTags); },
- get frequencies() { return getCachedValue(frequencies); },
- get pitches() { return getCachedValue(pitches); },
- get furiganaSegments() { return getCachedValue(furiganaSegments); },
- get termFrequency() { return getCachedValue(termFrequency); },
- wordClasses
- };
- results.push(item);
- }
- return results;
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @param {number} i
- * @returns {import('anki-templates').TermFrequency[]}
- */
-function getTermExpressionFrequencies(dictionaryEntry, i) {
- const results = [];
- const {headwords, frequencies} = dictionaryEntry;
- for (const {headwordIndex, dictionary, dictionaryIndex, dictionaryPriority, hasReading, frequency, displayValue} of frequencies) {
- if (headwordIndex !== i) { continue; }
- const {term, reading} = headwords[headwordIndex];
- results.push({
- index: results.length,
- expressionIndex: headwordIndex,
- dictionary,
- dictionaryOrder: {
- index: dictionaryIndex,
- priority: dictionaryPriority
- },
- expression: term,
- reading,
- hasReading,
- frequency: displayValue !== null ? displayValue : frequency
- });
- }
- return results;
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @param {number} i
- * @returns {import('anki-templates').TermPitchAccent[]}
- */
-function getTermExpressionPitches(dictionaryEntry, i) {
- const results = [];
- const {headwords, pronunciations: termPronunciations} = dictionaryEntry;
- for (const {headwordIndex, dictionary, dictionaryIndex, dictionaryPriority, pronunciations} of termPronunciations) {
- if (headwordIndex !== i) { continue; }
- const {term, reading} = headwords[headwordIndex];
- const pitches = getPronunciationsOfType(pronunciations, 'pitch-accent');
- const cachedPitches = createCachedValue(getTermPitchesInner.bind(null, pitches));
- results.push({
- index: results.length,
- expressionIndex: headwordIndex,
- dictionary,
- dictionaryOrder: {
- index: dictionaryIndex,
- priority: dictionaryPriority
- },
- expression: term,
- reading,
- get pitches() { return getCachedValue(cachedPitches); }
- });
- }
- return results;
-}
-
-/**
- * @param {import('anki-templates-internal').CachedValue<import('anki-templates').Tag[]>} cachedTermTags
- * @returns {import('anki-templates').TermFrequencyType}
- */
-function getTermExpressionTermFrequency(cachedTermTags) {
- const termTags = getCachedValue(cachedTermTags);
- return getTermFrequency(termTags);
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @param {import('anki-templates').TermDictionaryEntryType} type
- * @returns {import('dictionary-data').TermGlossary[]|undefined}
- */
-function getTermGlossaryArray(dictionaryEntry, type) {
- if (type === 'term') {
- const results = [];
- for (const {entries} of dictionaryEntry.definitions) {
- results.push(...entries);
- }
- return results;
- }
- return void 0;
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @param {import('anki-templates').TermDictionaryEntryType} type
- * @returns {import('anki-templates').Tag[]|undefined}
- */
-function getTermTags(dictionaryEntry, type) {
- if (type !== 'termMerged') {
- const results = [];
- for (const {tag} of groupTermTags(dictionaryEntry)) {
- results.push(convertTag(tag));
- }
- return results;
- }
- return void 0;
-}
-
-/**
- * @param {import('dictionary').Tag[]} tags
- * @returns {import('anki-templates').Tag[]}
- */
-function convertTags(tags) {
- const results = [];
- for (const tag of tags) {
- results.push(convertTag(tag));
- }
- return results;
-}
-
-/**
- * @param {import('dictionary').Tag} tag
- * @returns {import('anki-templates').Tag}
- */
-function convertTag({name, category, content, order, score, dictionaries, redundant}) {
- return {
- name,
- category,
- notes: (content.length > 0 ? content[0] : ''),
- order,
- score,
- dictionary: (dictionaries.length > 0 ? dictionaries[0] : ''),
- redundant
- };
-}
-
-/**
- * @param {import('dictionary').Tag[]} tags
- * @returns {import('anki-templates').PitchTag[]}
- */
-function convertPitchTags(tags) {
- const results = [];
- for (const tag of tags) {
- results.push(convertPitchTag(tag));
- }
- return results;
-}
-
-/**
- * @param {import('dictionary').Tag} tag
- * @returns {import('anki-templates').PitchTag}
- */
-function convertPitchTag({name, category, content, order, score, dictionaries, redundant}) {
- return {
- name,
- category,
- order,
- score,
- content: [...content],
- dictionaries: [...dictionaries],
- redundant
- };
-}
-
-/**
- * @param {import('dictionary').DictionaryEntry} dictionaryEntry
- * @param {import('anki-templates-internal').Context} context
- * @returns {import('anki-templates').Cloze}
- */
-function getCloze(dictionaryEntry, context) {
- let originalText = '';
- let term = '';
- let reading = '';
- switch (dictionaryEntry.type) {
- case 'term':
- {
- term = dictionaryEntry.headwords[0].term;
- reading = dictionaryEntry.headwords[0].reading;
- const primarySource = getPrimarySource(dictionaryEntry);
- if (primarySource !== null) { originalText = primarySource.originalText; }
- }
- break;
- case 'kanji':
- originalText = dictionaryEntry.character;
- break;
- }
-
- const {sentence} = context;
- let text;
- let offset;
- if (typeof sentence === 'object' && sentence !== null) {
- ({text, offset} = sentence);
- }
- if (typeof text !== 'string') { text = ''; }
- if (typeof offset !== 'number') { offset = 0; }
-
- const textSegments = [];
- for (const {text: text2, reading: reading2} of distributeFuriganaInflected(term, reading, text.substring(offset, offset + originalText.length))) {
- textSegments.push(reading2.length > 0 ? reading2 : text2);
- }
-
- return {
- sentence: text,
- prefix: text.substring(0, offset),
- body: text.substring(offset, offset + originalText.length),
- bodyKana: textSegments.join(''),
- suffix: text.substring(offset + originalText.length)
- };
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @param {import('anki-templates').TermDictionaryEntryType} type
- * @returns {import('anki-templates').FuriganaSegment[]|undefined}
- */
-function getTermFuriganaSegments(dictionaryEntry, type) {
- if (type === 'term') {
- for (const {term, reading} of dictionaryEntry.headwords) {
- return getTermHeadwordFuriganaSegments(term, reading);
- }
- }
- return void 0;
-}
-
-/**
- * @param {string} term
- * @param {string} reading
- * @returns {import('anki-templates').FuriganaSegment[]}
- */
-function getTermHeadwordFuriganaSegments(term, reading) {
- /** @type {import('anki-templates').FuriganaSegment[]} */
- const result = [];
- for (const {text, reading: reading2} of distributeFurigana(term, reading)) {
- result.push({text, furigana: reading2});
- }
- return result;
-}
-
-/**
- * @param {import('dictionary').TermDictionaryEntry} dictionaryEntry
- * @returns {number}
- */
-function getTermDictionaryEntrySequence(dictionaryEntry) {
- let hasSequence = false;
- let mainSequence = -1;
- if (!dictionaryEntry.isPrimary) { return mainSequence; }
- for (const {sequences} of dictionaryEntry.definitions) {
- const sequence = sequences[0];
- if (!hasSequence) {
- mainSequence = sequence;
- hasSequence = true;
- if (mainSequence === -1) { break; }
- } else if (mainSequence !== sequence) {
- mainSequence = -1;
- break;
- }
- }
- return mainSequence;
-}
diff --git a/ext/js/data/sandbox/array-buffer-util.js b/ext/js/data/sandbox/array-buffer-util.js
deleted file mode 100644
index 487fcd24..00000000
--- a/ext/js/data/sandbox/array-buffer-util.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2023-2024 Yomitan Authors
- * Copyright (C) 2021-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/>.
- */
-
-/**
- * Decodes the contents of an ArrayBuffer using UTF8.
- * @param {ArrayBuffer} arrayBuffer The input ArrayBuffer.
- * @returns {string} A UTF8-decoded string.
- */
-export function arrayBufferUtf8Decode(arrayBuffer) {
- try {
- return new TextDecoder('utf-8').decode(arrayBuffer);
- } catch (e) {
- return decodeURIComponent(escape(arrayBufferToBinaryString(arrayBuffer)));
- }
-}
-
-/**
- * Converts the contents of an ArrayBuffer to a base64 string.
- * @param {ArrayBuffer} arrayBuffer The input ArrayBuffer.
- * @returns {string} A base64 string representing the binary content.
- */
-export function arrayBufferToBase64(arrayBuffer) {
- return btoa(arrayBufferToBinaryString(arrayBuffer));
-}
-
-/**
- * Converts the contents of an ArrayBuffer to a binary string.
- * @param {ArrayBuffer} arrayBuffer The input ArrayBuffer.
- * @returns {string} A string representing the binary content.
- */
-export function arrayBufferToBinaryString(arrayBuffer) {
- const bytes = new Uint8Array(arrayBuffer);
- try {
- return String.fromCharCode(...bytes);
- } catch (e) {
- let binary = '';
- for (let i = 0, ii = bytes.byteLength; i < ii; ++i) {
- binary += String.fromCharCode(bytes[i]);
- }
- return binary;
- }
-}
-
-/**
- * Converts a base64 string to an ArrayBuffer.
- * @param {string} content The binary content string encoded in base64.
- * @returns {ArrayBuffer} A new `ArrayBuffer` object corresponding to the specified content.
- */
-export function base64ToArrayBuffer(content) {
- const binaryContent = atob(content);
- const length = binaryContent.length;
- const array = new Uint8Array(length);
- for (let i = 0; i < length; ++i) {
- array[i] = binaryContent.charCodeAt(i);
- }
- return array.buffer;
-}
diff --git a/ext/js/data/sandbox/string-util.js b/ext/js/data/sandbox/string-util.js
deleted file mode 100644
index 45e52f08..00000000
--- a/ext/js/data/sandbox/string-util.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2023-2024 Yomitan Authors
- * Copyright (C) 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/>.
- */
-
-/**
- * Reads code points from a string in the forward direction.
- * @param {string} text The text to read the code points from.
- * @param {number} position The index of the first character to read.
- * @param {number} count The number of code points to read.
- * @returns {string} The code points from the string.
- */
-export function readCodePointsForward(text, position, count) {
- const textLength = text.length;
- let result = '';
- for (; count > 0; --count) {
- const char = text[position];
- result += char;
- if (++position >= textLength) { break; }
- const charCode = char.charCodeAt(0);
- if (charCode >= 0xd800 && charCode < 0xdc00) { // charCode is a high surrogate code
- const char2 = text[position];
- const charCode2 = char2.charCodeAt(0);
- if (charCode2 >= 0xdc00 && charCode2 < 0xe000) { // charCode2 is a low surrogate code
- result += char2;
- if (++position >= textLength) { break; }
- }
- }
- }
- return result;
-}
-
-/**
- * Reads code points from a string in the backward direction.
- * @param {string} text The text to read the code points from.
- * @param {number} position The index of the first character to read.
- * @param {number} count The number of code points to read.
- * @returns {string} The code points from the string.
- */
-export function readCodePointsBackward(text, position, count) {
- let result = '';
- for (; count > 0; --count) {
- const char = text[position];
- result = char + result;
- if (--position < 0) { break; }
- const charCode = char.charCodeAt(0);
- if (charCode >= 0xdc00 && charCode < 0xe000) { // charCode is a low surrogate code
- const char2 = text[position];
- const charCode2 = char2.charCodeAt(0);
- if (charCode2 >= 0xd800 && charCode2 < 0xdc00) { // charCode2 is a high surrogate code
- result = char2 + result;
- if (--position < 0) { break; }
- }
- }
- }
- return result;
-}