diff options
Diffstat (limited to 'test')
26 files changed, 1085 insertions, 549 deletions
diff --git a/test/anki-note-builder.test.js b/test/anki-note-builder.test.js index e21aa993..96dacab6 100644 --- a/test/anki-note-builder.test.js +++ b/test/anki-note-builder.test.js @@ -26,8 +26,14 @@ import {TranslatorVM} from '../dev/translator-vm.js'; import {AnkiNoteBuilder} from '../ext/js/data/anki-note-builder.js'; import {JapaneseUtil} from '../ext/js/language/sandbox/japanese-util.js'; -vi.stubGlobal('fetch', async (url2) => { - const extDir = path.join(__dirname, '..', 'ext'); +const dirname = path.dirname(fileURLToPath(import.meta.url)); + +/** + * @param {string} url2 + * @returns {Promise<import('dev/vm').PseudoFetchResponse>} + */ +async function fetch(url2) { + const extDir = path.join(dirname, '..', 'ext'); let filePath; try { filePath = url.fileURLToPath(url2); @@ -43,11 +49,13 @@ vi.stubGlobal('fetch', async (url2) => { text: async () => Promise.resolve(content.toString('utf8')), json: async () => Promise.resolve(JSON.parse(content.toString('utf8'))) }; -}); +} +vi.stubGlobal('fetch', fetch); vi.mock('../ext/js/templates/template-renderer-proxy.js'); -const dirname = path.dirname(fileURLToPath(import.meta.url)); - +/** + * @returns {Promise<TranslatorVM>} + */ async function createVM() { const dictionaryDirectory = path.join(dirname, 'data', 'dictionaries', 'valid-dictionary1'); const vm = new TranslatorVM(); @@ -57,6 +65,10 @@ async function createVM() { return vm; } +/** + * @param {'terms'|'kanji'} type + * @returns {string[]} + */ function getFieldMarkers(type) { switch (type) { case 'terms': @@ -117,8 +129,17 @@ function getFieldMarkers(type) { } } +/** + * @param {import('dictionary').DictionaryEntry[]} dictionaryEntries + * @param {'terms'|'kanji'} type + * @param {import('settings').ResultOutputMode} mode + * @param {string} template + * @param {import('@vitest/expect').ExpectStatic} expect + * @returns {Promise<import('anki').NoteFields[]>} + */ async function getRenderResults(dictionaryEntries, type, mode, template, expect) { const markers = getFieldMarkers(type); + /** @type {import('anki-note-builder').Field[]} */ const fields = []; for (const marker of markers) { fields.push([marker, `{${marker}}`]); @@ -151,9 +172,10 @@ async function getRenderResults(dictionaryEntries, type, mode, template, expect) query: 'query', fullQuery: 'fullQuery' }; - const {note: {fields: noteFields}, errors} = await ankiNoteBuilder.createNote({ + /** @type {import('anki-note-builder').CreateNoteDetails} */ + const details = { dictionaryEntry, - mode: null, + mode: 'test', context, template, deckName: 'deckName', @@ -165,8 +187,11 @@ async function getRenderResults(dictionaryEntries, type, mode, template, expect) duplicateScopeCheckAllModels: false, resultOutputMode: mode, glossaryLayoutMode: 'default', - compactTags: false - }); + compactTags: false, + requirements: [], + mediaOptions: null + }; + const {note: {fields: noteFields}, errors} = await ankiNoteBuilder.createNote(details); for (const error of errors) { console.error(error); } @@ -178,6 +203,7 @@ async function getRenderResults(dictionaryEntries, type, mode, template, expect) } +/** */ async function main() { const vm = await createVM(); @@ -199,6 +225,7 @@ async function main() { case 'findTerms': { const {name, mode, text} = t; + /** @type {import('translation').FindTermsOptions} */ const options = vm.buildOptions(optionsPresets, t.options); const {dictionaryEntries} = structuredClone(await vm.translator.findTerms(mode, text, options)); const results = mode !== 'simple' ? structuredClone(await getRenderResults(dictionaryEntries, 'terms', mode, template, expect)) : null; @@ -209,9 +236,10 @@ async function main() { case 'findKanji': { const {name, text} = t; + /** @type {import('translation').FindKanjiOptions} */ const options = vm.buildOptions(optionsPresets, t.options); const dictionaryEntries = structuredClone(await vm.translator.findKanji(text, options)); - const results = structuredClone(await getRenderResults(dictionaryEntries, 'kanji', null, template, expect)); + const results = structuredClone(await getRenderResults(dictionaryEntries, 'kanji', 'split', template, expect)); actualResults1.push({name, results}); expect(results).toStrictEqual(expected1.results); } diff --git a/test/cache-map.test.js b/test/cache-map.test.js index 9d10a719..df891188 100644 --- a/test/cache-map.test.js +++ b/test/cache-map.test.js @@ -19,6 +19,7 @@ import {expect, test} from 'vitest'; import {CacheMap} from '../ext/js/general/cache-map.js'; +/** */ function testConstructor() { test('constructor', () => { const data = [ @@ -29,6 +30,7 @@ function testConstructor() { [true, () => new CacheMap(1.5)], [true, () => new CacheMap(Number.NaN)], [true, () => new CacheMap(Number.POSITIVE_INFINITY)], + // @ts-expect-error - Ignore because it should throw an error [true, () => new CacheMap('a')] ]; @@ -42,6 +44,7 @@ function testConstructor() { }); } +/** */ function testApi() { test('api', () => { const data = [ @@ -103,10 +106,10 @@ function testApi() { const {func, args} = call; let returnValue; switch (func) { - case 'get': returnValue = cache.get(...args); break; - case 'set': returnValue = cache.set(...args); break; - case 'has': returnValue = cache.has(...args); break; - case 'clear': returnValue = cache.clear(...args); break; + case 'get': returnValue = cache.get(args[0]); break; + case 'set': returnValue = cache.set(args[0], args[1]); break; + case 'has': returnValue = cache.has(args[0]); break; + case 'clear': returnValue = cache.clear(); break; } if (Object.prototype.hasOwnProperty.call(call, 'returnValue')) { const {returnValue: expectedReturnValue} = call; @@ -119,6 +122,7 @@ function testApi() { } +/** */ function main() { testConstructor(); testApi(); diff --git a/test/core.test.js b/test/core.test.js index 203460f4..685bf9dc 100644 --- a/test/core.test.js +++ b/test/core.test.js @@ -19,14 +19,17 @@ import {describe, expect, test} from 'vitest'; import {DynamicProperty, deepEqual} from '../ext/js/core.js'; +/** */ function testDynamicProperty() { test('DynamicProperty', () => { const data = [ { initialValue: 0, + /** @type {{operation: ?string, expectedDefaultValue: number, expectedValue: number, expectedOverrideCount: number, expeectedEventOccurred: boolean, args: [value: number, priority?: number]}[]} */ operations: [ { operation: null, + args: [0], expectedDefaultValue: 0, expectedValue: 0, expectedOverrideCount: 0, @@ -147,6 +150,7 @@ function testDynamicProperty() { }); } +/** */ function testDeepEqual() { describe('deepEqual', () => { const data = [ @@ -280,6 +284,7 @@ function testDeepEqual() { } +/** */ function main() { testDynamicProperty(); testDeepEqual(); diff --git a/test/css-json.test.js b/test/css-json.test.js index 0aaf7d10..66ecfeba 100644 --- a/test/css-json.test.js +++ b/test/css-json.test.js @@ -20,6 +20,7 @@ import fs from 'fs'; import {expect, test} from 'vitest'; import {formatRulesJson, generateRules, getTargets} from '../dev/generate-css-json'; +/** */ function main() { test('css-json', () => { for (const {cssFile, overridesCssFile, outputPath} of getTargets()) { diff --git a/test/data/anki-note-builder-test-results.json b/test/data/anki-note-builder-test-results.json index b752e878..49542e39 100644 --- a/test/data/anki-note-builder-test-results.json +++ b/test/data/anki-note-builder-test-results.json @@ -194,7 +194,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 22</li><li>Test Dictionary 2: 28</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: sixteen</li><li>Test Dictionary 2: twenty-two (22)</li><li>Test Dictionary 2: 28</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>つ", "furigana-plain": "打[う]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>utsu definition 3</li><li>utsu definition 4</li></ul></div>", @@ -224,7 +224,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 23</li><li>Test Dictionary 2: 29</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: seventeen</li><li>Test Dictionary 2: twenty-three (23)</li><li>Test Dictionary 2: twenty-nine</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>つ", "furigana-plain": "打[ぶ]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>butsu definition 3</li><li>butsu definition 4</li></ul></div>", @@ -379,7 +379,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打ち込む", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: 7</li><li>Test Dictionary 2: 12</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 24</li><li>Test Dictionary 2: 30</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: seven</li><li>Test Dictionary 2: 12</li><li>Test Dictionary 2: eighteen</li><li>Test Dictionary 2: twenty-four (24)</li><li>Test Dictionary 2: 30</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>ち<ruby>込<rt>こ</rt></ruby>む", "furigana-plain": "打[う]ち 込[こ]む", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>uchikomu definition 3</li><li>uchikomu definition 4</li></ul></div>", @@ -409,7 +409,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打ち込む", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: 7</li><li>Test Dictionary 2: 13</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 25</li><li>Test Dictionary 2: 31</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: seven</li><li>Test Dictionary 2: 13</li><li>Test Dictionary 2: nineteen</li><li>Test Dictionary 2: twenty-five (25)</li><li>Test Dictionary 2: thirty-one</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>ち<ruby>込<rt>こ</rt></ruby>む", "furigana-plain": "打[ぶ]ち 込[こ]む", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>buchikomu definition 3</li><li>buchikomu definition 4</li></ul></div>", @@ -499,7 +499,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 22</li><li>Test Dictionary 2: 28</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: sixteen</li><li>Test Dictionary 2: twenty-two (22)</li><li>Test Dictionary 2: 28</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>つ", "furigana-plain": "打[う]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>utsu definition 3</li><li>utsu definition 4</li></ul></div>", @@ -529,7 +529,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 23</li><li>Test Dictionary 2: 29</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: seventeen</li><li>Test Dictionary 2: twenty-three (23)</li><li>Test Dictionary 2: twenty-nine</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>つ", "furigana-plain": "打[ぶ]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>butsu definition 3</li><li>butsu definition 4</li></ul></div>", @@ -759,7 +759,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 22</li><li>Test Dictionary 2: 28</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: sixteen</li><li>Test Dictionary 2: twenty-two (22)</li><li>Test Dictionary 2: 28</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>つ", "furigana-plain": "打[う]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>utsu definition 3</li><li>utsu definition 4</li></ul></div>", @@ -824,7 +824,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 23</li><li>Test Dictionary 2: 29</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: seventeen</li><li>Test Dictionary 2: twenty-three (23)</li><li>Test Dictionary 2: twenty-nine</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>つ", "furigana-plain": "打[ぶ]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>butsu definition 3</li><li>butsu definition 4</li></ul></div>", @@ -889,7 +889,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打ち込む", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: 7</li><li>Test Dictionary 2: 12</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 24</li><li>Test Dictionary 2: 30</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: seven</li><li>Test Dictionary 2: 12</li><li>Test Dictionary 2: eighteen</li><li>Test Dictionary 2: twenty-four (24)</li><li>Test Dictionary 2: 30</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>ち<ruby>込<rt>こ</rt></ruby>む", "furigana-plain": "打[う]ち 込[こ]む", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>uchikomu definition 3</li><li>uchikomu definition 4</li></ul></div>", @@ -949,7 +949,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 22</li><li>Test Dictionary 2: 28</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: sixteen</li><li>Test Dictionary 2: twenty-two (22)</li><li>Test Dictionary 2: 28</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>つ", "furigana-plain": "打[う]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>utsu definition 3</li><li>utsu definition 4</li></ul></div>", @@ -1014,7 +1014,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打ち込む", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: 7</li><li>Test Dictionary 2: 13</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 25</li><li>Test Dictionary 2: 31</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: seven</li><li>Test Dictionary 2: 13</li><li>Test Dictionary 2: nineteen</li><li>Test Dictionary 2: twenty-five (25)</li><li>Test Dictionary 2: thirty-one</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>ち<ruby>込<rt>こ</rt></ruby>む", "furigana-plain": "打[ぶ]ち 込[こ]む", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>buchikomu definition 3</li><li>buchikomu definition 4</li></ul></div>", @@ -1074,7 +1074,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 23</li><li>Test Dictionary 2: 29</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: seventeen</li><li>Test Dictionary 2: twenty-three (23)</li><li>Test Dictionary 2: twenty-nine</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>つ", "furigana-plain": "打[ぶ]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>butsu definition 3</li><li>butsu definition 4</li></ul></div>", @@ -1526,7 +1526,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打ち込む", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: 7</li><li>Test Dictionary 2: 12</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 24</li><li>Test Dictionary 2: 30</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: seven</li><li>Test Dictionary 2: 12</li><li>Test Dictionary 2: eighteen</li><li>Test Dictionary 2: twenty-four (24)</li><li>Test Dictionary 2: 30</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>ち<ruby>込<rt>こ</rt></ruby>む", "furigana-plain": "打[う]ち 込[こ]む", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>uchikomu definition 3</li><li>uchikomu definition 4</li></ul></div>", @@ -1556,7 +1556,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打ち込む", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: 7</li><li>Test Dictionary 2: 13</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 25</li><li>Test Dictionary 2: 31</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: seven</li><li>Test Dictionary 2: 13</li><li>Test Dictionary 2: nineteen</li><li>Test Dictionary 2: twenty-five (25)</li><li>Test Dictionary 2: thirty-one</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>ち<ruby>込<rt>こ</rt></ruby>む", "furigana-plain": "打[ぶ]ち 込[こ]む", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>buchikomu definition 3</li><li>buchikomu definition 4</li></ul></div>", @@ -1646,7 +1646,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 22</li><li>Test Dictionary 2: 28</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: sixteen</li><li>Test Dictionary 2: twenty-two (22)</li><li>Test Dictionary 2: 28</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>つ", "furigana-plain": "打[う]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>utsu definition 3</li><li>utsu definition 4</li></ul></div>", @@ -1676,7 +1676,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 23</li><li>Test Dictionary 2: 29</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: seventeen</li><li>Test Dictionary 2: twenty-three (23)</li><li>Test Dictionary 2: twenty-nine</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>つ", "furigana-plain": "打[ぶ]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>butsu definition 3</li><li>butsu definition 4</li></ul></div>", @@ -1831,7 +1831,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打ち込む", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: 7</li><li>Test Dictionary 2: 12</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 24</li><li>Test Dictionary 2: 30</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: seven</li><li>Test Dictionary 2: 12</li><li>Test Dictionary 2: eighteen</li><li>Test Dictionary 2: twenty-four (24)</li><li>Test Dictionary 2: 30</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>ち<ruby>込<rt>こ</rt></ruby>む", "furigana-plain": "打[う]ち 込[こ]む", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>uchikomu definition 3</li><li>uchikomu definition 4</li></ul></div>", @@ -1861,7 +1861,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打ち込む", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: 7</li><li>Test Dictionary 2: 13</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 25</li><li>Test Dictionary 2: 31</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: seven</li><li>Test Dictionary 2: 13</li><li>Test Dictionary 2: nineteen</li><li>Test Dictionary 2: twenty-five (25)</li><li>Test Dictionary 2: thirty-one</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>ち<ruby>込<rt>こ</rt></ruby>む", "furigana-plain": "打[ぶ]ち 込[こ]む", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>buchikomu definition 3</li><li>buchikomu definition 4</li></ul></div>", @@ -1951,7 +1951,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 22</li><li>Test Dictionary 2: 28</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: sixteen</li><li>Test Dictionary 2: twenty-two (22)</li><li>Test Dictionary 2: 28</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>つ", "furigana-plain": "打[う]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>utsu definition 3</li><li>utsu definition 4</li></ul></div>", @@ -1981,7 +1981,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 23</li><li>Test Dictionary 2: 29</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: seventeen</li><li>Test Dictionary 2: twenty-three (23)</li><li>Test Dictionary 2: twenty-nine</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>つ", "furigana-plain": "打[ぶ]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>butsu definition 3</li><li>butsu definition 4</li></ul></div>", @@ -2136,7 +2136,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打ち込む", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: 7</li><li>Test Dictionary 2: 12</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 24</li><li>Test Dictionary 2: 30</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: seven</li><li>Test Dictionary 2: 12</li><li>Test Dictionary 2: eighteen</li><li>Test Dictionary 2: twenty-four (24)</li><li>Test Dictionary 2: 30</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>ち<ruby>込<rt>こ</rt></ruby>む", "furigana-plain": "打[う]ち 込[こ]む", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>uchikomu definition 3</li><li>uchikomu definition 4</li></ul></div>", @@ -2166,7 +2166,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打ち込む", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: 7</li><li>Test Dictionary 2: 13</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 25</li><li>Test Dictionary 2: 31</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 3</li><li>Test Dictionary 2: seven</li><li>Test Dictionary 2: 13</li><li>Test Dictionary 2: nineteen</li><li>Test Dictionary 2: twenty-five (25)</li><li>Test Dictionary 2: thirty-one</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>ち<ruby>込<rt>こ</rt></ruby>む", "furigana-plain": "打[ぶ]ち 込[こ]む", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>buchikomu definition 3</li><li>buchikomu definition 4</li></ul></div>", @@ -2256,7 +2256,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 22</li><li>Test Dictionary 2: 28</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 10</li><li>Test Dictionary 2: sixteen</li><li>Test Dictionary 2: twenty-two (22)</li><li>Test Dictionary 2: 28</li></ul>", "furigana": "<ruby>打<rt>う</rt></ruby>つ", "furigana-plain": "打[う]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>utsu definition 3</li><li>utsu definition 4</li></ul></div>", @@ -2286,7 +2286,7 @@ "dictionary": "Test Dictionary 2", "document-title": "title", "expression": "打つ", - "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: 0</li><li>Test Dictionary 2: 23</li><li>Test Dictionary 2: 29</li></ul>", + "frequencies": "<ul style=\"text-align: left;\"><li>Test Dictionary 2: 2</li><li>Test Dictionary 2: 6</li><li>Test Dictionary 2: 11</li><li>Test Dictionary 2: seventeen</li><li>Test Dictionary 2: twenty-three (23)</li><li>Test Dictionary 2: twenty-nine</li></ul>", "furigana": "<ruby>打<rt>ぶ</rt></ruby>つ", "furigana-plain": "打[ぶ]つ", "glossary": "<div style=\"text-align: left;\"><i>(vt, Test Dictionary 2)</i> <ul><li>butsu definition 3</li><li>butsu definition 4</li></ul></div>", diff --git a/test/data/html/test-document2-script.js b/test/data/html/test-document2-script.js index 8a183019..f6082802 100644 --- a/test/data/html/test-document2-script.js +++ b/test/data/html/test-document2-script.js @@ -16,40 +16,65 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +/** + * @param {Element} element + */ function requestFullscreen(element) { if (element.requestFullscreen) { element.requestFullscreen(); + // @ts-expect-error - Browser compatibility } else if (element.mozRequestFullScreen) { + // @ts-expect-error - Browser compatibility element.mozRequestFullScreen(); + // @ts-expect-error - Browser compatibility } else if (element.webkitRequestFullscreen) { + // @ts-expect-error - Browser compatibility element.webkitRequestFullscreen(); + // @ts-expect-error - Browser compatibility } else if (element.msRequestFullscreen) { + // @ts-expect-error - Browser compatibility element.msRequestFullscreen(); } } +/** */ function exitFullscreen() { if (document.exitFullscreen) { document.exitFullscreen(); + // @ts-expect-error - Browser compatibility } else if (document.mozCancelFullScreen) { + // @ts-expect-error - Browser compatibility document.mozCancelFullScreen(); + // @ts-expect-error - Browser compatibility } else if (document.webkitExitFullscreen) { + // @ts-expect-error - Browser compatibility document.webkitExitFullscreen(); + // @ts-expect-error - Browser compatibility } else if (document.msExitFullscreen) { + // @ts-expect-error - Browser compatibility document.msExitFullscreen(); } } +/** + * @returns {?Element} + */ function getFullscreenElement() { return ( document.fullscreenElement || + // @ts-expect-error - Browser compatibility document.msFullscreenElement || + // @ts-expect-error - Browser compatibility document.mozFullScreenElement || + // @ts-expect-error - Browser compatibility document.webkitFullscreenElement || null ); } +/** + * @param {Element} element + */ function toggleFullscreen(element) { if (getFullscreenElement()) { exitFullscreen(); @@ -58,6 +83,10 @@ function toggleFullscreen(element) { } } +/** + * @param {HTMLElement|DocumentFragment} container + * @param {?Element} [fullscreenElement] + */ function setup(container, fullscreenElement=null) { const fullscreenLink = container.querySelector('.fullscreen-link'); if (fullscreenLink !== null) { @@ -65,6 +94,7 @@ function setup(container, fullscreenElement=null) { fullscreenElement = container.querySelector('.fullscreen-element'); } fullscreenLink.addEventListener('click', (e) => { + if (fullscreenElement === null) { return; } toggleFullscreen(fullscreenElement); e.preventDefault(); return false; @@ -74,11 +104,15 @@ function setup(container, fullscreenElement=null) { const template = container.querySelector('template'); const templateContentContainer = container.querySelector('.template-content-container'); if (template !== null && templateContentContainer !== null) { - const mode = container.dataset.shadowMode; - const shadow = templateContentContainer.attachShadow({mode}); + const mode = (container instanceof HTMLElement ? container.dataset.shadowMode : void 0); + const shadow = templateContentContainer.attachShadow({ + mode: (mode === 'open' || mode === 'closed' ? mode : 'open') + }); const containerStyles = document.querySelector('#container-styles'); - shadow.appendChild(containerStyles.cloneNode(true)); + if (containerStyles !== null) { + shadow.appendChild(containerStyles.cloneNode(true)); + } const content = document.importNode(template.content, true); setup(content); diff --git a/test/data/translator-test-results-note-data1.json b/test/data/translator-test-results-note-data1.json index d686563c..34f7c21a 100644 --- a/test/data/translator-test-results-note-data1.json +++ b/test/data/translator-test-results-note-data1.json @@ -1659,7 +1659,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -1672,7 +1672,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -1791,7 +1791,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -1804,7 +1804,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -1963,7 +1963,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -1976,7 +1976,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -1989,7 +1989,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -2095,7 +2095,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -2108,7 +2108,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -2121,7 +2121,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -3651,7 +3651,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -3677,7 +3677,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 0 + "frequency": "eighteen" }, { "index": 4, @@ -3690,7 +3690,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 24 + "frequency": "twenty-four (24)" }, { "index": 5, @@ -3813,7 +3813,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -3839,7 +3839,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 0 + "frequency": "eighteen" }, { "index": 4, @@ -3852,7 +3852,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 24 + "frequency": "twenty-four (24)" }, { "index": 5, @@ -4045,7 +4045,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -4071,7 +4071,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 0 + "frequency": "nineteen" }, { "index": 4, @@ -4084,7 +4084,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 25 + "frequency": "twenty-five (25)" }, { "index": 5, @@ -4097,7 +4097,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 31 + "frequency": "thirty-one" } ], "pitches": [ @@ -4207,7 +4207,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -4233,7 +4233,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 0 + "frequency": "nineteen" }, { "index": 4, @@ -4246,7 +4246,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 25 + "frequency": "twenty-five (25)" }, { "index": 5, @@ -4259,7 +4259,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 31 + "frequency": "thirty-one" } ], "pitches": [ @@ -5079,7 +5079,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -5092,7 +5092,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -5211,7 +5211,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -5224,7 +5224,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -5385,7 +5385,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -5398,7 +5398,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -5411,7 +5411,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -5517,7 +5517,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -5530,7 +5530,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -5543,7 +5543,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -7394,7 +7394,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -7407,7 +7407,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -7526,7 +7526,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -7539,7 +7539,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -8007,7 +8007,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -8020,7 +8020,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -8033,7 +8033,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -8139,7 +8139,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -8152,7 +8152,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -8165,7 +8165,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -8684,7 +8684,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -8710,7 +8710,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 0 + "frequency": "eighteen" }, { "index": 4, @@ -8723,7 +8723,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 24 + "frequency": "twenty-four (24)" }, { "index": 5, @@ -8846,7 +8846,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -8872,7 +8872,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 0 + "frequency": "eighteen" }, { "index": 4, @@ -8885,7 +8885,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 24 + "frequency": "twenty-four (24)" }, { "index": 5, @@ -9412,7 +9412,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -9425,7 +9425,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -9544,7 +9544,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -9557,7 +9557,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -10089,7 +10089,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -10115,7 +10115,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 0 + "frequency": "nineteen" }, { "index": 4, @@ -10128,7 +10128,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 25 + "frequency": "twenty-five (25)" }, { "index": 5, @@ -10141,7 +10141,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 31 + "frequency": "thirty-one" } ], "pitches": [ @@ -10251,7 +10251,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -10277,7 +10277,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 0 + "frequency": "nineteen" }, { "index": 4, @@ -10290,7 +10290,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 25 + "frequency": "twenty-five (25)" }, { "index": 5, @@ -10303,7 +10303,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 31 + "frequency": "thirty-one" } ], "pitches": [ @@ -10817,7 +10817,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -10830,7 +10830,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -10843,7 +10843,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -10949,7 +10949,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -10962,7 +10962,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -10975,7 +10975,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -16097,7 +16097,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -16123,7 +16123,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 0 + "frequency": "eighteen" }, { "index": 4, @@ -16136,7 +16136,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 24 + "frequency": "twenty-four (24)" }, { "index": 5, @@ -16259,7 +16259,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -16285,7 +16285,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 0 + "frequency": "eighteen" }, { "index": 4, @@ -16298,7 +16298,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 24 + "frequency": "twenty-four (24)" }, { "index": 5, @@ -16495,7 +16495,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -16521,7 +16521,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 0 + "frequency": "nineteen" }, { "index": 4, @@ -16534,7 +16534,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 25 + "frequency": "twenty-five (25)" }, { "index": 5, @@ -16547,7 +16547,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 31 + "frequency": "thirty-one" } ], "pitches": [ @@ -16657,7 +16657,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -16683,7 +16683,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 0 + "frequency": "nineteen" }, { "index": 4, @@ -16696,7 +16696,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 25 + "frequency": "twenty-five (25)" }, { "index": 5, @@ -16709,7 +16709,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 31 + "frequency": "thirty-one" } ], "pitches": [ @@ -17529,7 +17529,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -17542,7 +17542,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -17661,7 +17661,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -17674,7 +17674,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -17835,7 +17835,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -17848,7 +17848,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -17861,7 +17861,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -17967,7 +17967,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -17980,7 +17980,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -17993,7 +17993,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -19523,7 +19523,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -19549,7 +19549,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 0 + "frequency": "eighteen" }, { "index": 4, @@ -19562,7 +19562,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 24 + "frequency": "twenty-four (24)" }, { "index": 5, @@ -19685,7 +19685,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -19711,7 +19711,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 0 + "frequency": "eighteen" }, { "index": 4, @@ -19724,7 +19724,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 24 + "frequency": "twenty-four (24)" }, { "index": 5, @@ -19917,7 +19917,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -19943,7 +19943,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 0 + "frequency": "nineteen" }, { "index": 4, @@ -19956,7 +19956,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 25 + "frequency": "twenty-five (25)" }, { "index": 5, @@ -19969,7 +19969,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 31 + "frequency": "thirty-one" } ], "pitches": [ @@ -20079,7 +20079,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -20105,7 +20105,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 0 + "frequency": "nineteen" }, { "index": 4, @@ -20118,7 +20118,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 25 + "frequency": "twenty-five (25)" }, { "index": 5, @@ -20131,7 +20131,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 31 + "frequency": "thirty-one" } ], "pitches": [ @@ -20951,7 +20951,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -20964,7 +20964,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -21083,7 +21083,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -21096,7 +21096,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -21257,7 +21257,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -21270,7 +21270,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -21283,7 +21283,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -21389,7 +21389,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -21402,7 +21402,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -21415,7 +21415,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -22945,7 +22945,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -22971,7 +22971,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 0 + "frequency": "eighteen" }, { "index": 4, @@ -22984,7 +22984,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 24 + "frequency": "twenty-four (24)" }, { "index": 5, @@ -23107,7 +23107,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -23133,7 +23133,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 0 + "frequency": "eighteen" }, { "index": 4, @@ -23146,7 +23146,7 @@ "expression": "打ち込む", "reading": "うちこむ", "hasReading": true, - "frequency": 24 + "frequency": "twenty-four (24)" }, { "index": 5, @@ -23339,7 +23339,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -23365,7 +23365,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 0 + "frequency": "nineteen" }, { "index": 4, @@ -23378,7 +23378,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 25 + "frequency": "twenty-five (25)" }, { "index": 5, @@ -23391,7 +23391,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 31 + "frequency": "thirty-one" } ], "pitches": [ @@ -23501,7 +23501,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": false, - "frequency": 7 + "frequency": "seven" }, { "index": 2, @@ -23527,7 +23527,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 0 + "frequency": "nineteen" }, { "index": 4, @@ -23540,7 +23540,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 25 + "frequency": "twenty-five (25)" }, { "index": 5, @@ -23553,7 +23553,7 @@ "expression": "打ち込む", "reading": "ぶちこむ", "hasReading": true, - "frequency": 31 + "frequency": "thirty-one" } ], "pitches": [ @@ -24373,7 +24373,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -24386,7 +24386,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -24505,7 +24505,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 0 + "frequency": "sixteen" }, { "index": 4, @@ -24518,7 +24518,7 @@ "expression": "打つ", "reading": "うつ", "hasReading": true, - "frequency": 22 + "frequency": "twenty-two (22)" }, { "index": 5, @@ -24679,7 +24679,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -24692,7 +24692,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -24705,7 +24705,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], @@ -24811,7 +24811,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 0 + "frequency": "seventeen" }, { "index": 4, @@ -24824,7 +24824,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 23 + "frequency": "twenty-three (23)" }, { "index": 5, @@ -24837,7 +24837,7 @@ "expression": "打つ", "reading": "ぶつ", "hasReading": true, - "frequency": 29 + "frequency": "twenty-nine" } ], "pitches": [], diff --git a/test/data/translator-test-results.json b/test/data/translator-test-results.json index 98db0ef4..0a7155b8 100644 --- a/test/data/translator-test-results.json +++ b/test/data/translator-test-results.json @@ -1101,8 +1101,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "sixteen", + "displayValueParsed": true }, { "index": 4, @@ -1112,8 +1112,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 22, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-two (22)", + "displayValueParsed": true }, { "index": 5, @@ -1266,8 +1266,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "seventeen", + "displayValueParsed": true }, { "index": 4, @@ -1277,8 +1277,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 23, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-three (23)", + "displayValueParsed": true }, { "index": 5, @@ -1288,7 +1288,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 29, - "displayValue": null, + "displayValue": "twenty-nine", "displayValueParsed": false } ] @@ -2150,7 +2150,7 @@ "dictionaryPriority": 0, "hasReading": false, "frequency": 7, - "displayValue": null, + "displayValue": "seven", "displayValueParsed": false }, { @@ -2172,8 +2172,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "eighteen", + "displayValueParsed": true }, { "index": 4, @@ -2183,8 +2183,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 24, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-four (24)", + "displayValueParsed": true }, { "index": 5, @@ -2337,7 +2337,7 @@ "dictionaryPriority": 0, "hasReading": false, "frequency": 7, - "displayValue": null, + "displayValue": "seven", "displayValueParsed": false }, { @@ -2359,8 +2359,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "nineteen", + "displayValueParsed": true }, { "index": 4, @@ -2370,8 +2370,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 25, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-five (25)", + "displayValueParsed": true }, { "index": 5, @@ -2381,7 +2381,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 31, - "displayValue": null, + "displayValue": "thirty-one", "displayValueParsed": false } ] @@ -2860,8 +2860,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "sixteen", + "displayValueParsed": true }, { "index": 4, @@ -2871,8 +2871,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 22, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-two (22)", + "displayValueParsed": true }, { "index": 5, @@ -3027,8 +3027,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "seventeen", + "displayValueParsed": true }, { "index": 4, @@ -3038,8 +3038,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 23, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-three (23)", + "displayValueParsed": true }, { "index": 5, @@ -3049,7 +3049,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 29, - "displayValue": null, + "displayValue": "twenty-nine", "displayValueParsed": false } ] @@ -4166,8 +4166,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "sixteen", + "displayValueParsed": true }, { "index": 4, @@ -4177,8 +4177,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 22, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-two (22)", + "displayValueParsed": true }, { "index": 5, @@ -4502,8 +4502,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "seventeen", + "displayValueParsed": true }, { "index": 4, @@ -4513,8 +4513,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 23, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-three (23)", + "displayValueParsed": true }, { "index": 5, @@ -4524,7 +4524,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 29, - "displayValue": null, + "displayValue": "twenty-nine", "displayValueParsed": false } ] @@ -4860,7 +4860,7 @@ "dictionaryPriority": 0, "hasReading": false, "frequency": 7, - "displayValue": null, + "displayValue": "seven", "displayValueParsed": false }, { @@ -4882,8 +4882,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "eighteen", + "displayValueParsed": true }, { "index": 4, @@ -4893,8 +4893,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 24, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-four (24)", + "displayValueParsed": true }, { "index": 5, @@ -5216,8 +5216,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "sixteen", + "displayValueParsed": true }, { "index": 4, @@ -5227,8 +5227,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 22, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-two (22)", + "displayValueParsed": true }, { "index": 5, @@ -5574,7 +5574,7 @@ "dictionaryPriority": 0, "hasReading": false, "frequency": 7, - "displayValue": null, + "displayValue": "seven", "displayValueParsed": false }, { @@ -5596,8 +5596,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "nineteen", + "displayValueParsed": true }, { "index": 4, @@ -5607,8 +5607,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 25, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-five (25)", + "displayValueParsed": true }, { "index": 5, @@ -5618,7 +5618,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 31, - "displayValue": null, + "displayValue": "thirty-one", "displayValueParsed": false } ] @@ -5930,8 +5930,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "seventeen", + "displayValueParsed": true }, { "index": 4, @@ -5941,8 +5941,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 23, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-three (23)", + "displayValueParsed": true }, { "index": 5, @@ -5952,7 +5952,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 29, - "displayValue": null, + "displayValue": "twenty-nine", "displayValueParsed": false } ] @@ -9645,7 +9645,7 @@ "dictionaryPriority": 0, "hasReading": false, "frequency": 7, - "displayValue": null, + "displayValue": "seven", "displayValueParsed": false }, { @@ -9667,8 +9667,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "eighteen", + "displayValueParsed": true }, { "index": 4, @@ -9678,8 +9678,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 24, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-four (24)", + "displayValueParsed": true }, { "index": 5, @@ -9836,7 +9836,7 @@ "dictionaryPriority": 0, "hasReading": false, "frequency": 7, - "displayValue": null, + "displayValue": "seven", "displayValueParsed": false }, { @@ -9858,8 +9858,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "nineteen", + "displayValueParsed": true }, { "index": 4, @@ -9869,8 +9869,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 25, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-five (25)", + "displayValueParsed": true }, { "index": 5, @@ -9880,7 +9880,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 31, - "displayValue": null, + "displayValue": "thirty-one", "displayValueParsed": false } ] @@ -10359,8 +10359,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "sixteen", + "displayValueParsed": true }, { "index": 4, @@ -10370,8 +10370,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 22, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-two (22)", + "displayValueParsed": true }, { "index": 5, @@ -10526,8 +10526,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "seventeen", + "displayValueParsed": true }, { "index": 4, @@ -10537,8 +10537,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 23, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-three (23)", + "displayValueParsed": true }, { "index": 5, @@ -10548,7 +10548,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 29, - "displayValue": null, + "displayValue": "twenty-nine", "displayValueParsed": false } ] @@ -11410,7 +11410,7 @@ "dictionaryPriority": 0, "hasReading": false, "frequency": 7, - "displayValue": null, + "displayValue": "seven", "displayValueParsed": false }, { @@ -11432,8 +11432,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "eighteen", + "displayValueParsed": true }, { "index": 4, @@ -11443,8 +11443,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 24, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-four (24)", + "displayValueParsed": true }, { "index": 5, @@ -11597,7 +11597,7 @@ "dictionaryPriority": 0, "hasReading": false, "frequency": 7, - "displayValue": null, + "displayValue": "seven", "displayValueParsed": false }, { @@ -11619,8 +11619,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "nineteen", + "displayValueParsed": true }, { "index": 4, @@ -11630,8 +11630,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 25, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-five (25)", + "displayValueParsed": true }, { "index": 5, @@ -11641,7 +11641,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 31, - "displayValue": null, + "displayValue": "thirty-one", "displayValueParsed": false } ] @@ -12120,8 +12120,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "sixteen", + "displayValueParsed": true }, { "index": 4, @@ -12131,8 +12131,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 22, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-two (22)", + "displayValueParsed": true }, { "index": 5, @@ -12287,8 +12287,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "seventeen", + "displayValueParsed": true }, { "index": 4, @@ -12298,8 +12298,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 23, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-three (23)", + "displayValueParsed": true }, { "index": 5, @@ -12309,7 +12309,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 29, - "displayValue": null, + "displayValue": "twenty-nine", "displayValueParsed": false } ] @@ -13171,7 +13171,7 @@ "dictionaryPriority": 0, "hasReading": false, "frequency": 7, - "displayValue": null, + "displayValue": "seven", "displayValueParsed": false }, { @@ -13193,8 +13193,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "eighteen", + "displayValueParsed": true }, { "index": 4, @@ -13204,8 +13204,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 24, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-four (24)", + "displayValueParsed": true }, { "index": 5, @@ -13358,7 +13358,7 @@ "dictionaryPriority": 0, "hasReading": false, "frequency": 7, - "displayValue": null, + "displayValue": "seven", "displayValueParsed": false }, { @@ -13380,8 +13380,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "nineteen", + "displayValueParsed": true }, { "index": 4, @@ -13391,8 +13391,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 25, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-five (25)", + "displayValueParsed": true }, { "index": 5, @@ -13402,7 +13402,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 31, - "displayValue": null, + "displayValue": "thirty-one", "displayValueParsed": false } ] @@ -13881,8 +13881,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "sixteen", + "displayValueParsed": true }, { "index": 4, @@ -13892,8 +13892,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 22, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-two (22)", + "displayValueParsed": true }, { "index": 5, @@ -14048,8 +14048,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 0, - "displayValue": null, - "displayValueParsed": false + "displayValue": "seventeen", + "displayValueParsed": true }, { "index": 4, @@ -14059,8 +14059,8 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 23, - "displayValue": null, - "displayValueParsed": false + "displayValue": "twenty-three (23)", + "displayValueParsed": true }, { "index": 5, @@ -14070,7 +14070,7 @@ "dictionaryPriority": 0, "hasReading": true, "frequency": 29, - "displayValue": null, + "displayValue": "twenty-nine", "displayValueParsed": false } ] diff --git a/test/database.test.js b/test/database.test.js index b53d0e65..80871f95 100644 --- a/test/database.test.js +++ b/test/database.test.js @@ -17,6 +17,7 @@ */ import {IDBFactory, IDBKeyRange} from 'fake-indexeddb'; +import {fileURLToPath} from 'node:url'; import path from 'path'; import {beforeEach, describe, expect, test, vi} from 'vitest'; import {createDictionaryArchive} from '../dev/util.js'; @@ -24,16 +25,27 @@ import {DictionaryDatabase} from '../ext/js/language/dictionary-database.js'; import {DictionaryImporterMediaLoader} from '../ext/js/language/dictionary-importer-media-loader.js'; import {DictionaryImporter} from '../ext/js/language/dictionary-importer.js'; +const dirname = path.dirname(fileURLToPath(import.meta.url)); + vi.stubGlobal('IDBKeyRange', IDBKeyRange); vi.mock('../ext/js/language/dictionary-importer-media-loader.js'); +/** + * @param {string} dictionary + * @param {string} [dictionaryName] + * @returns {import('jszip')} + */ function createTestDictionaryArchive(dictionary, dictionaryName) { - const dictionaryDirectory = path.join(__dirname, 'data', 'dictionaries', dictionary); + const dictionaryDirectory = path.join(dirname, 'data', 'dictionaries', dictionary); return createDictionaryArchive(dictionaryDirectory, dictionaryName); } +/** + * @param {import('dictionary-importer').OnProgressCallback} [onProgress] + * @returns {DictionaryImporter} + */ function createDictionaryImporter(onProgress) { const dictionaryImporterMediaLoader = new DictionaryImporterMediaLoader(); return new DictionaryImporter(dictionaryImporterMediaLoader, (...args) => { @@ -47,24 +59,53 @@ function createDictionaryImporter(onProgress) { } +/** + * @param {import('dictionary-database').TermEntry[]} dictionaryDatabaseEntries + * @param {string} term + * @returns {number} + */ function countDictionaryDatabaseEntriesWithTerm(dictionaryDatabaseEntries, term) { return dictionaryDatabaseEntries.reduce((i, v) => (i + (v.term === term ? 1 : 0)), 0); } +/** + * @param {import('dictionary-database').TermEntry[]} dictionaryDatabaseEntries + * @param {string} reading + * @returns {number} + */ function countDictionaryDatabaseEntriesWithReading(dictionaryDatabaseEntries, reading) { return dictionaryDatabaseEntries.reduce((i, v) => (i + (v.reading === reading ? 1 : 0)), 0); } +/** + * @param {import('dictionary-database').TermMeta[]|import('dictionary-database').KanjiMeta[]} metas + * @param {import('dictionary-database').TermMetaType|import('dictionary-database').KanjiMetaType} mode + * @returns {number} + */ function countMetasWithMode(metas, mode) { - return metas.reduce((i, v) => (i + (v.mode === mode ? 1 : 0)), 0); + let i = 0; + for (const item of metas) { + if (item.mode === mode) { ++i; } + } + return i; } +/** + * @param {import('dictionary-database').KanjiEntry[]} kanji + * @param {string} character + * @returns {number} + */ function countKanjiWithCharacter(kanji, character) { - return kanji.reduce((i, v) => (i + (v.character === character ? 1 : 0)), 0); + let i = 0; + for (const item of kanji) { + if (item.character === character) { ++i; } + } + return i; } +/** */ async function testDatabase1() { test('Database1', async () => { // Load dictionary data const testDictionary = createTestDictionaryArchive('valid-dictionary1'); @@ -172,6 +213,9 @@ async function testDatabase1() { }); } +/** + * @param {DictionaryDatabase} database + */ async function testDatabaseEmpty1(database) { test('DatabaseEmpty1', async () => { const info = await database.getDictionaryInfo(); @@ -185,17 +229,22 @@ async function testDatabaseEmpty1(database) { }); } +/** + * @param {DictionaryDatabase} database + * @param {import('dictionary-database').DictionarySet} titles + */ async function testFindTermsBulkTest1(database, titles) { test('FindTermsBulkTest1', async () => { + /** @type {{inputs: {matchType: import('dictionary-database').MatchType, termList: string[]}[], expectedResults: {total: number, terms: [key: string, count: number][], readings: [key: string, count: number][]}}[]} */ const data = [ { inputs: [ { - matchType: null, + matchType: 'exact', termList: ['打', '打つ', '打ち込む'] }, { - matchType: null, + matchType: 'exact', termList: ['だ', 'ダース', 'うつ', 'ぶつ', 'うちこむ', 'ぶちこむ'] }, { @@ -223,7 +272,7 @@ async function testFindTermsBulkTest1(database, titles) { { inputs: [ { - matchType: null, + matchType: 'exact', termList: ['込む'] } ], @@ -254,7 +303,7 @@ async function testFindTermsBulkTest1(database, titles) { { inputs: [ { - matchType: null, + matchType: 'exact', termList: [] } ], @@ -281,8 +330,13 @@ async function testFindTermsBulkTest1(database, titles) { }); } +/** + * @param {DictionaryDatabase} database + * @param {import('dictionary-database').DictionarySet} titles + */ async function testTindTermsExactBulk1(database, titles) { test('TindTermsExactBulk1', async () => { + /** @type {{inputs: {termList: {term: string, reading: string}[]}[], expectedResults: {total: number, terms: [key: string, count: number][], readings: [key: string, count: number][]}}[]} */ const data = [ { inputs: [ @@ -387,8 +441,13 @@ async function testTindTermsExactBulk1(database, titles) { }); } +/** + * @param {DictionaryDatabase} database + * @param {string} mainDictionary + */ async function testFindTermsBySequenceBulk1(database, mainDictionary) { test('FindTermsBySequenceBulk1', async () => { + /** @type {{inputs: {sequenceList: number[]}[], expectedResults: {total: number, terms: [key: string, count: number][], readings: [key: string, count: number][]}}[]} */ const data = [ { inputs: [ @@ -538,8 +597,13 @@ async function testFindTermsBySequenceBulk1(database, mainDictionary) { }); } +/** + * @param {DictionaryDatabase} database + * @param {import('dictionary-database').DictionarySet} titles + */ async function testFindTermMetaBulk1(database, titles) { test('FindTermMetaBulk1', async () => { + /** @type {{inputs: {termList: string[]}[], expectedResults: {total: number, modes: [key: import('dictionary-database').TermMetaType, count: number][]}}[]} */ const data = [ { inputs: [ @@ -606,8 +670,13 @@ async function testFindTermMetaBulk1(database, titles) { }); } +/** + * @param {DictionaryDatabase} database + * @param {import('dictionary-database').DictionarySet} titles + */ async function testFindKanjiBulk1(database, titles) { test('FindKanjiBulk1', async () => { + /** @type {{inputs: {kanjiList: string[]}[], expectedResults: {total: number, kanji: [key: string, count: number][]}}[]} */ const data = [ { inputs: [ @@ -660,8 +729,13 @@ async function testFindKanjiBulk1(database, titles) { }); } +/** + * @param {DictionaryDatabase} database + * @param {import('dictionary-database').DictionarySet} titles + */ async function testFindKanjiMetaBulk1(database, titles) { test('FindKanjiMetaBulk1', async () => { + /** @type {{inputs: {kanjiList: string[]}[], expectedResults: {total: number, modes: [key: import('dictionary-database').KanjiMetaType, count: number][]}}[]} */ const data = [ { inputs: [ @@ -714,6 +788,10 @@ async function testFindKanjiMetaBulk1(database, titles) { }); } +/** + * @param {DictionaryDatabase} database + * @param {string} title + */ async function testFindTagForTitle1(database, title) { test('FindTagForTitle1', async () => { const data = [ @@ -769,6 +847,7 @@ async function testFindTagForTitle1(database, title) { } +/** */ async function testDatabase2() { test('Database2', async () => { // Load dictionary data const testDictionary = createTestDictionaryArchive('valid-dictionary1'); @@ -782,10 +861,12 @@ async function testDatabase2() { // Setup database const dictionaryDatabase = new DictionaryDatabase(); + /** @type {import('dictionary-importer').ImportDetails} */ + const detaultImportDetails = {prefixWildcardsSupported: false}; // Database not open - await expect(dictionaryDatabase.deleteDictionary(title, 1000)).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.findTermsBulk(['?'], titles, null)).rejects.toThrow('Database not open'); + await expect(dictionaryDatabase.deleteDictionary(title, 1000, () => {})).rejects.toThrow('Database not open'); + await expect(dictionaryDatabase.findTermsBulk(['?'], titles, 'exact')).rejects.toThrow('Database not open'); await expect(dictionaryDatabase.findTermsExactBulk([{term: '?', reading: '?'}], titles)).rejects.toThrow('Database not open'); await expect(dictionaryDatabase.findTermsBySequenceBulk([{query: 1, dictionary: title}])).rejects.toThrow('Database not open'); await expect(dictionaryDatabase.findTermMetaBulk(['?'], titles)).rejects.toThrow('Database not open'); @@ -794,24 +875,25 @@ async function testDatabase2() { await expect(dictionaryDatabase.findKanjiMetaBulk(['?'], titles)).rejects.toThrow('Database not open'); await expect(dictionaryDatabase.findTagForTitle('tag', title)).rejects.toThrow('Database not open'); await expect(dictionaryDatabase.getDictionaryInfo()).rejects.toThrow('Database not open'); - await expect(dictionaryDatabase.getDictionaryCounts(titles, true)).rejects.toThrow('Database not open'); - await expect(createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, {})).rejects.toThrow('Database is not ready'); + await expect(dictionaryDatabase.getDictionaryCounts([...titles.keys()], true)).rejects.toThrow('Database not open'); + await expect(createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Database is not ready'); await dictionaryDatabase.prepare(); // already prepared await expect(dictionaryDatabase.prepare()).rejects.toThrow('Database already open'); - await createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, {}); + await createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails); // dictionary already imported - await expect(createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, {})).rejects.toThrow('Dictionary is already imported'); + await expect(createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Dictionary is already imported'); await dictionaryDatabase.close(); }); } +/** */ async function testDatabase3() { const invalidDictionaries = [ 'invalid-dictionary1', @@ -828,12 +910,14 @@ async function testDatabase3() { test(`${invalidDictionary}`, async () => { // Setup database const dictionaryDatabase = new DictionaryDatabase(); + /** @type {import('dictionary-importer').ImportDetails} */ + const detaultImportDetails = {prefixWildcardsSupported: false}; await dictionaryDatabase.prepare(); const testDictionary = createTestDictionaryArchive(invalidDictionary); const testDictionarySource = await testDictionary.generateAsync({type: 'arraybuffer'}); - await expect(createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, {})).rejects.toThrow('Dictionary has invalid data'); + await expect(createDictionaryImporter().importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Dictionary has invalid data'); await dictionaryDatabase.close(); }); } @@ -841,6 +925,7 @@ async function testDatabase3() { } +/** */ async function main() { beforeEach(async () => { globalThis.indexedDB = new IDBFactory(); diff --git a/test/deinflector.test.js b/test/deinflector.test.js index edb85833..bd538428 100644 --- a/test/deinflector.test.js +++ b/test/deinflector.test.js @@ -17,12 +17,23 @@ */ import fs from 'fs'; +import {fileURLToPath} from 'node:url'; import path from 'path'; import {describe, expect, test} from 'vitest'; import {Deinflector} from '../ext/js/language/deinflector.js'; +const dirname = path.dirname(fileURLToPath(import.meta.url)); + +/** + * @param {Deinflector} deinflector + * @param {string} source + * @param {string} expectedTerm + * @param {string} expectedRule + * @param {string[]|undefined} expectedReasons + * @returns {{has: false, reasons: null, rules: null}|{has: true, reasons: string[], rules: number}} + */ function hasTermReasons(deinflector, source, expectedTerm, expectedRule, expectedReasons) { - for (const {term, reasons, rules} of deinflector.deinflect(source, source)) { + for (const {term, reasons, rules} of deinflector.deinflect(source)) { if (term !== expectedTerm) { continue; } if (typeof expectedRule !== 'undefined') { const expectedFlags = Deinflector.rulesToRuleFlags([expectedRule]); @@ -46,6 +57,7 @@ function hasTermReasons(deinflector, source, expectedTerm, expectedRule, expecte } +/** */ function testDeinflections() { const data = [ { @@ -915,7 +927,7 @@ function testDeinflections() { } ]; - const deinflectionReasons = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'ext', 'data/deinflect.json'))); + const deinflectionReasons = JSON.parse(fs.readFileSync(path.join(dirname, '..', 'ext', 'data/deinflect.json'), {encoding: 'utf8'})); const deinflector = new Deinflector(deinflectionReasons); describe('deinflections', () => { @@ -939,6 +951,7 @@ function testDeinflections() { } +/** */ function main() { testDeinflections(); } diff --git a/test/dictionary.test.js b/test/dictionary.test.js index 8f160bc1..e516bd8e 100644 --- a/test/dictionary.test.js +++ b/test/dictionary.test.js @@ -24,12 +24,18 @@ import {createDictionaryArchive} from '../dev/util.js'; const dirname = path.dirname(fileURLToPath(import.meta.url)); +/** + * @param {string} dictionary + * @param {string} [dictionaryName] + * @returns {import('jszip')} + */ function createTestDictionaryArchive(dictionary, dictionaryName) { const dictionaryDirectory = path.join(dirname, 'data', 'dictionaries', dictionary); return createDictionaryArchive(dictionaryDirectory, dictionaryName); } +/** */ async function main() { const dictionaries = [ {name: 'valid-dictionary1', valid: true}, diff --git a/test/document-util.test.js b/test/document-util.test.js index f2552f78..8c6ab69b 100644 --- a/test/document-util.test.js +++ b/test/document-util.test.js @@ -30,24 +30,48 @@ const dirname = path.dirname(fileURLToPath(import.meta.url)); // DOMRect class definition class DOMRect { + /** + * @param {number} x + * @param {number} y + * @param {number} width + * @param {number} height + */ constructor(x, y, width, height) { + /** @type {number} */ this._x = x; + /** @type {number} */ this._y = y; + /** @type {number} */ this._width = width; + /** @type {number} */ this._height = height; } + /** @type {number} */ get x() { return this._x; } + /** @type {number} */ get y() { return this._y; } + /** @type {number} */ get width() { return this._width; } + /** @type {number} */ get height() { return this._height; } + /** @type {number} */ get left() { return this._x + Math.min(0, this._width); } + /** @type {number} */ get right() { return this._x + Math.max(0, this._width); } + /** @type {number} */ get top() { return this._y + Math.min(0, this._height); } + /** @type {number} */ get bottom() { return this._y + Math.max(0, this._height); } + /** @returns {string} */ + toJSON() { return '<not implemented>'; } } +/** + * @param {string} fileName + * @returns {JSDOM} + */ function createJSDOM(fileName) { const domSource = fs.readFileSync(fileName, {encoding: 'utf8'}); const dom = new JSDOM(domSource); @@ -65,10 +89,20 @@ function createJSDOM(fileName) { return dom; } +/** + * @param {Element} element + * @param {string|undefined} selector + * @returns {?Element} + */ function querySelectorChildOrSelf(element, selector) { return selector ? element.querySelector(selector) : element; } +/** + * @param {JSDOM} dom + * @param {?Node} node + * @returns {?Text|Node} + */ function getChildTextNodeOrSelf(dom, node) { if (node === null) { return null; } const Node = dom.window.Node; @@ -76,6 +110,10 @@ function getChildTextNodeOrSelf(dom, node) { return (childNode !== null && childNode.nodeType === Node.TEXT_NODE ? childNode : node); } +/** + * @param {unknown} value + * @returns {unknown} + */ function getPrototypeOfOrNull(value) { try { return Object.getPrototypeOf(value); @@ -84,12 +122,17 @@ function getPrototypeOfOrNull(value) { } } +/** + * @param {Document} document + * @returns {?Element} + */ function findImposterElement(document) { // Finds the imposter element based on it's z-index style return document.querySelector('div[style*="2147483646"]>*'); } +/** */ async function testDocument1() { const dom = createJSDOM(path.join(dirname, 'data', 'html', 'test-document1.html')); const window = dom.window; @@ -102,13 +145,16 @@ async function testDocument1() { } } +/** + * @param {JSDOM} dom + */ async function testDocumentTextScanningFunctions(dom) { const document = dom.window.document; test('DocumentTextScanningFunctions', () => { - for (const testElement of document.querySelectorAll('.test[data-test-type=scan]')) { - // Get test parameters - let { + for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('.test[data-test-type=scan]'))) { + // Get test parameters + const { elementFromPointSelector, caretRangeFromPointSelector, startNodeSelector, @@ -127,10 +173,10 @@ async function testDocumentTextScanningFunctions(dom) { const startNode = getChildTextNodeOrSelf(dom, querySelectorChildOrSelf(testElement, startNodeSelector)); const endNode = getChildTextNodeOrSelf(dom, querySelectorChildOrSelf(testElement, endNodeSelector)); - startOffset = parseInt(startOffset, 10); - endOffset = parseInt(endOffset, 10); - sentenceScanExtent = parseInt(sentenceScanExtent, 10); - terminateAtNewlines = (terminateAtNewlines !== 'false'); + const startOffset2 = parseInt(/** @type {string} */ (startOffset), 10); + const endOffset2 = parseInt(/** @type {string} */ (endOffset), 10); + const sentenceScanExtent2 = parseInt(/** @type {string} */ (sentenceScanExtent), 10); + const terminateAtNewlines2 = (terminateAtNewlines !== 'false'); expect(elementFromPointValue).not.toStrictEqual(null); expect(caretRangeFromPointValue).not.toStrictEqual(null); @@ -145,11 +191,25 @@ async function testDocumentTextScanningFunctions(dom) { expect(!!imposter).toStrictEqual(hasImposter === 'true'); const range = document.createRange(); - range.setStart(imposter ? imposter : startNode, startOffset); - range.setEnd(imposter ? imposter : startNode, endOffset); + range.setStart(/** @type {Node} */ (imposter ? imposter : startNode), startOffset2); + range.setEnd(/** @type {Node} */ (imposter ? imposter : startNode), endOffset2); // Override getClientRects to return a rect guaranteed to contain (x, y) - range.getClientRects = () => [new DOMRect(x - 1, y - 1, 2, 2)]; + range.getClientRects = () => { + /** @type {import('test/document-types').PseudoDOMRectList} */ + const domRectList = Object.assign( + [new DOMRect(x - 1, y - 1, 2, 2)], + { + /** + * @this {DOMRect[]} + * @param {number} index + * @returns {DOMRect} + */ + item: function item(index) { return this[index]; } + } + ); + return domRectList; + }; return range; }; @@ -192,8 +252,8 @@ async function testDocumentTextScanningFunctions(dom) { const sentenceActual = DocumentUtil.extractSentence( source, false, - sentenceScanExtent, - terminateAtNewlines, + sentenceScanExtent2, + terminateAtNewlines2, terminatorMap, forwardQuoteMap, backwardQuoteMap @@ -206,13 +266,16 @@ async function testDocumentTextScanningFunctions(dom) { }); } +/** + * @param {JSDOM} dom + */ async function testTextSourceRangeSeekFunctions(dom) { const document = dom.window.document; test('TextSourceRangeSeekFunctions', async () => { - for (const testElement of document.querySelectorAll('.test[data-test-type=text-source-range-seek]')) { - // Get test parameters - let { + for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('.test[data-test-type=text-source-range-seek]'))) { + // Get test parameters + const { seekNodeSelector, seekNodeIsText, seekOffset, @@ -224,34 +287,37 @@ async function testTextSourceRangeSeekFunctions(dom) { expectedResultContent } = testElement.dataset; - seekOffset = parseInt(seekOffset, 10); - seekLength = parseInt(seekLength, 10); - expectedResultOffset = parseInt(expectedResultOffset, 10); + const seekOffset2 = parseInt(/** @type {string} */ (seekOffset), 10); + const seekLength2 = parseInt(/** @type {string} */ (seekLength), 10); + const expectedResultOffset2 = parseInt(/** @type {string} */ (expectedResultOffset), 10); - let seekNode = testElement.querySelector(seekNodeSelector); - if (seekNodeIsText === 'true') { + /** @type {?Node} */ + let seekNode = testElement.querySelector(/** @type {string} */ (seekNodeSelector)); + if (seekNodeIsText === 'true' && seekNode !== null) { seekNode = seekNode.firstChild; } - let expectedResultNode = testElement.querySelector(expectedResultNodeSelector); - if (expectedResultNodeIsText === 'true') { + /** @type {?Node} */ + let expectedResultNode = testElement.querySelector(/** @type {string} */ (expectedResultNodeSelector)); + if (expectedResultNodeIsText === 'true' && expectedResultNode !== null) { expectedResultNode = expectedResultNode.firstChild; } const {node, offset, content} = ( - seekDirection === 'forward' ? - new DOMTextScanner(seekNode, seekOffset, true, false).seek(seekLength) : - new DOMTextScanner(seekNode, seekOffset, true, false).seek(-seekLength) + seekDirection === 'forward' ? + new DOMTextScanner(/** @type {Node} */ (seekNode), seekOffset2, true, false).seek(seekLength2) : + new DOMTextScanner(/** @type {Node} */ (seekNode), seekOffset2, true, false).seek(-seekLength2) ); expect(node).toStrictEqual(expectedResultNode); - expect(offset).toStrictEqual(expectedResultOffset); + expect(offset).toStrictEqual(expectedResultOffset2); expect(content).toStrictEqual(expectedResultContent); } }); } +/** */ async function main() { await testDocument1(); } diff --git a/test/dom-text-scanner.test.js b/test/dom-text-scanner.test.js index d1b31276..f6a7410a 100644 --- a/test/dom-text-scanner.test.js +++ b/test/dom-text-scanner.test.js @@ -18,15 +18,27 @@ import fs from 'fs'; import {JSDOM} from 'jsdom'; +import {fileURLToPath} from 'node:url'; import path from 'path'; import {expect, test} from 'vitest'; import {DOMTextScanner} from '../ext/js/dom/dom-text-scanner.js'; +const dirname = path.dirname(fileURLToPath(import.meta.url)); + +/** + * @param {string} fileName + * @returns {JSDOM} + */ function createJSDOM(fileName) { const domSource = fs.readFileSync(fileName, {encoding: 'utf8'}); return new JSDOM(domSource); } +/** + * @param {Element} element + * @param {string} selector + * @returns {?Node} + */ function querySelectorTextNode(element, selector) { let textIndex = -1; const match = /::text$|::nth-text\((\d+)\)$/.exec(selector); @@ -35,13 +47,16 @@ function querySelectorTextNode(element, selector) { selector = selector.substring(0, selector.length - match[0].length); } const result = element.querySelector(selector); + if (result === null) { + return null; + } if (textIndex < 0) { return result; } for (let n = result.firstChild; n !== null; n = n.nextSibling) { - if (n.nodeType === n.constructor.TEXT_NODE) { + if (n.nodeType === /** @type {typeof Node} */ (n.constructor).TEXT_NODE) { if (textIndex === 0) { - return n; + return /** @type {Text} */ (n); } --textIndex; } @@ -50,10 +65,16 @@ function querySelectorTextNode(element, selector) { } +/** + * @param {import('jsdom').DOMWindow} window + * @param {(element: Element) => CSSStyleDeclaration} getComputedStyle + * @param {?Node} element + * @returns {number} + */ function getComputedFontSizeInPixels(window, getComputedStyle, element) { for (; element !== null; element = element.parentNode) { if (element.nodeType === window.Node.ELEMENT_NODE) { - const fontSize = getComputedStyle(element).fontSize; + const fontSize = getComputedStyle(/** @type {Element} */ (element)).fontSize; if (fontSize.endsWith('px')) { const value = parseFloat(fontSize.substring(0, fontSize.length - 2)); return value; @@ -64,14 +85,19 @@ function getComputedFontSizeInPixels(window, getComputedStyle, element) { return defaultFontSize; } +/** + * @param {import('jsdom').DOMWindow} window + * @returns {(element: Element, pseudoElement?: ?string) => CSSStyleDeclaration} + */ function createAbsoluteGetComputedStyle(window) { // Wrapper to convert em units to px units const getComputedStyleOld = window.getComputedStyle.bind(window); + /** @type {(element: Element, pseudoElement?: ?string) => CSSStyleDeclaration} */ return (element, ...args) => { const style = getComputedStyleOld(element, ...args); return new Proxy(style, { get: (target, property) => { - let result = target[property]; + let result = /** @type {import('core').SafeAny} */ (target)[property]; if (typeof result === 'string') { result = result.replace(/([-+]?\d(?:\.\d)?(?:[eE][-+]?\d+)?)em/g, (g0, g1) => { const fontSize = getComputedFontSizeInPixels(window, getComputedStyleOld, element); @@ -85,12 +111,15 @@ function createAbsoluteGetComputedStyle(window) { } +/** + * @param {JSDOM} dom + */ async function testDomTextScanner(dom) { const document = dom.window.document; test('DomTextScanner', () => { - for (const testElement of document.querySelectorAll('y-test')) { - let testData = JSON.parse(testElement.dataset.testData); + for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('y-test'))) { + let testData = JSON.parse(/** @type {string} */ (testElement.dataset.testData)); if (!Array.isArray(testData)) { testData = [testData]; } @@ -159,19 +188,21 @@ async function testDomTextScanner(dom) { } +/** */ async function testDocument1() { - const dom = createJSDOM(path.join(__dirname, 'data', 'html', 'test-dom-text-scanner.html')); + const dom = createJSDOM(path.join(dirname, 'data', 'html', 'test-dom-text-scanner.html')); const window = dom.window; try { window.getComputedStyle = createAbsoluteGetComputedStyle(window); - await testDomTextScanner(dom, {DOMTextScanner}); + await testDomTextScanner(dom); } finally { window.close(); } } +/** */ async function main() { await testDocument1(); } diff --git a/test/hotkey-util.test.js b/test/hotkey-util.test.js index 8666b98b..02622c40 100644 --- a/test/hotkey-util.test.js +++ b/test/hotkey-util.test.js @@ -19,8 +19,10 @@ import {expect, test} from 'vitest'; import {HotkeyUtil} from '../ext/js/input/hotkey-util.js'; +/** */ function testCommandConversions() { test('CommandConversions', () => { + /** @type {{os: import('environment').OperatingSystem, command: string, expectedCommand: string, expectedInput: {key: string, modifiers: import('input').Modifier[]}}[]} */ const data = [ {os: 'win', command: 'Alt+F', expectedCommand: 'Alt+F', expectedInput: {key: 'KeyF', modifiers: ['alt']}}, {os: 'win', command: 'F1', expectedCommand: 'F1', expectedInput: {key: 'F1', modifiers: []}}, @@ -49,8 +51,10 @@ function testCommandConversions() { }); } +/** */ function testDisplayNames() { test('DisplayNames', () => { + /** @type {{os: import('environment').OperatingSystem, key: ?string, modifiers: import('input').Modifier[], expected: string}[]} */ const data = [ {os: 'win', key: null, modifiers: [], expected: ''}, {os: 'win', key: 'KeyF', modifiers: [], expected: 'F'}, @@ -138,8 +142,10 @@ function testDisplayNames() { }); } +/** */ function testSortModifiers() { test('SortModifiers', () => { + /** @type {{modifiers: import('input').Modifier[], expected: import('input').Modifier[]}[]} */ const data = [ {modifiers: [], expected: []}, {modifiers: ['shift', 'alt', 'ctrl', 'mouse4', 'meta', 'mouse1', 'mouse0'], expected: ['meta', 'ctrl', 'alt', 'shift', 'mouse0', 'mouse1', 'mouse4']} @@ -155,6 +161,7 @@ function testSortModifiers() { } +/** */ function main() { testCommandConversions(); testDisplayNames(); diff --git a/test/japanese-util.test.js b/test/japanese-util.test.js index 47da4ccb..a0078da0 100644 --- a/test/japanese-util.test.js +++ b/test/japanese-util.test.js @@ -23,8 +23,10 @@ import * as wanakana from '../ext/lib/wanakana.js'; const jp = new JapaneseUtil(wanakana); +/** */ function testIsCodePointKanji() { test('isCodePointKanji', () => { + /** @type {[characters: string, expected: boolean][]} */ const data = [ ['力方', true], ['\u53f1\u{20b9f}', true], @@ -34,7 +36,7 @@ function testIsCodePointKanji() { for (const [characters, expected] of data) { for (const character of characters) { - const codePoint = character.codePointAt(0); + const codePoint = /** @type {number} */ (character.codePointAt(0)); const actual = jp.isCodePointKanji(codePoint); expect(actual).toStrictEqual(expected); // `isCodePointKanji failed for ${character} (\\u{${codePoint.toString(16)}})` } @@ -42,8 +44,10 @@ function testIsCodePointKanji() { }); } +/** */ function testIsCodePointKana() { test('isCodePointKana', () => { + /** @type {[characters: string, expected: boolean][]} */ const data = [ ['かたカタ', true], ['力方々kata、。?,.?', false], @@ -52,7 +56,7 @@ function testIsCodePointKana() { for (const [characters, expected] of data) { for (const character of characters) { - const codePoint = character.codePointAt(0); + const codePoint = /** @type {number} */ (character.codePointAt(0)); const actual = jp.isCodePointKana(codePoint); expect(actual).toStrictEqual(expected); // `isCodePointKana failed for ${character} (\\u{${codePoint.toString(16)}})` } @@ -60,8 +64,10 @@ function testIsCodePointKana() { }); } +/** */ function testIsCodePointJapanese() { test('isCodePointJapanese', () => { + /** @type {[characters: string, expected: boolean][]} */ const data = [ ['かたカタ力方々、。?', true], ['\u53f1\u{20b9f}', true], @@ -71,7 +77,7 @@ function testIsCodePointJapanese() { for (const [characters, expected] of data) { for (const character of characters) { - const codePoint = character.codePointAt(0); + const codePoint = /** @type {number} */ (character.codePointAt(0)); const actual = jp.isCodePointJapanese(codePoint); expect(actual).toStrictEqual(expected); // `isCodePointJapanese failed for ${character} (\\u{${codePoint.toString(16)}})` } @@ -79,8 +85,10 @@ function testIsCodePointJapanese() { }); } +/** */ function testIsStringEntirelyKana() { test('isStringEntirelyKana', () => { + /** @type {[string: string, expected: boolean][]} */ const data = [ ['かたかな', true], ['カタカナ', true], @@ -101,8 +109,10 @@ function testIsStringEntirelyKana() { }); } +/** */ function testIsStringPartiallyJapanese() { test('isStringPartiallyJapanese', () => { + /** @type {[string: string, expected: boolean][]} */ const data = [ ['かたかな', true], ['カタカナ', true], @@ -124,8 +134,10 @@ function testIsStringPartiallyJapanese() { }); } +/** */ function testConvertKatakanaToHiragana() { test('convertKatakanaToHiragana', () => { + /** @type {[string: string, expected: string, keepProlongedSoundMarks?: boolean][]} */ const data = [ ['かたかな', 'かたかな'], ['ひらがな', 'ひらがな'], @@ -146,8 +158,10 @@ function testConvertKatakanaToHiragana() { }); } +/** */ function testConvertHiraganaToKatakana() { test('ConvertHiraganaToKatakana', () => { + /** @type {[string: string, expected: string][]} */ const data = [ ['かたかな', 'カタカナ'], ['ひらがな', 'ヒラガナ'], @@ -166,8 +180,10 @@ function testConvertHiraganaToKatakana() { }); } +/** */ function testConvertToRomaji() { test('ConvertToRomaji', () => { + /** @type {[string: string, expected: string][]} */ const data = [ ['かたかな', 'katakana'], ['ひらがな', 'hiragana'], @@ -186,8 +202,10 @@ function testConvertToRomaji() { }); } +/** */ function testConvertNumericToFullWidth() { test('ConvertNumericToFullWidth', () => { + /** @type {[string: string, expected: string][]} */ const data = [ ['0123456789', '0123456789'], ['abcdefghij', 'abcdefghij'], @@ -201,8 +219,10 @@ function testConvertNumericToFullWidth() { }); } +/** */ function testConvertHalfWidthKanaToFullWidth() { test('ConvertHalfWidthKanaToFullWidth', () => { + /** @type {[string: string, expected: string, expectedSourceMapping?: number[]][]} */ const data = [ ['0123456789', '0123456789'], ['abcdefghij', 'abcdefghij'], @@ -227,8 +247,10 @@ function testConvertHalfWidthKanaToFullWidth() { }); } +/** */ function testConvertAlphabeticToKana() { test('ConvertAlphabeticToKana', () => { + /** @type {[string: string, expected: string, expectedSourceMapping?: number[]][]} */ const data = [ ['0123456789', '0123456789'], ['abcdefghij', 'あbcでfgひj', [1, 1, 1, 2, 1, 1, 2, 1]], @@ -252,8 +274,10 @@ function testConvertAlphabeticToKana() { }); } +/** */ function testDistributeFurigana() { test('DistributeFurigana', () => { + /** @type {[input: [term: string, reading: string], expected: {text: string, reading: string}[]][]} */ const data = [ [ ['有り難う', 'ありがとう'], @@ -719,8 +743,10 @@ function testDistributeFurigana() { }); } +/** */ function testDistributeFuriganaInflected() { test('DistributeFuriganaInflected', () => { + /** @type {[input: [term: string, reading: string, source: string], expected: {text: string, reading: string}[]][]} */ const data = [ [ ['美味しい', 'おいしい', '美味しかた'], @@ -770,8 +796,10 @@ function testDistributeFuriganaInflected() { }); } +/** */ function testCollapseEmphaticSequences() { test('CollapseEmphaticSequences', () => { + /** @type {[input: [text: string, fullCollapse: boolean], output: [expected: string, expectedSourceMapping: number[]]][]} */ const data = [ [['かこい', false], ['かこい', [1, 1, 1]]], [['かこい', true], ['かこい', [1, 1, 1]]], @@ -825,8 +853,10 @@ function testCollapseEmphaticSequences() { }); } +/** */ function testIsMoraPitchHigh() { test('IsMoraPitchHigh', () => { + /** @type {[input: [moraIndex: number, pitchAccentDownstepPosition: number], expected: boolean][]} */ const data = [ [[0, 0], false], [[1, 0], true], @@ -861,8 +891,10 @@ function testIsMoraPitchHigh() { }); } +/** */ function testGetKanaMorae() { test('GetKanaMorae', () => { + /** @type {[text: string, expected: string[]][]} */ const data = [ ['かこ', ['か', 'こ']], ['かっこ', ['か', 'っ', 'こ']], @@ -883,6 +915,7 @@ function testGetKanaMorae() { } +/** */ function main() { testIsCodePointKanji(); testIsCodePointKana(); diff --git a/test/jsconfig.json b/test/jsconfig.json new file mode 100644 index 00000000..c587abe6 --- /dev/null +++ b/test/jsconfig.json @@ -0,0 +1,40 @@ +{ + "compilerOptions": { + "module": "ES2022", + "target": "ES2022", + "checkJs": true, + "moduleResolution": "node", + "strict": true, + "strictNullChecks": true, + "noImplicitAny": true, + "strictPropertyInitialization": true, + "suppressImplicitAnyIndexErrors": false, + "skipLibCheck": false, + "baseUrl": ".", + "paths": { + "*": ["../types/ext/*"], + "dev/*": ["../types/dev/*"], + "test/*": ["../types/test/*"], + "rollup/parseAst": ["../types/other/rollup-parse-ast"] + }, + "types": [ + "chrome", + "firefox-webext-browser", + "handlebars", + "jszip", + "parse5", + "wanakana" + ] + }, + "include": [ + "**/*.js", + "../ext/**/*.js", + "../types/ext/**/*.ts", + "../types/dev/**/*.ts", + "../types/other/globals.d.ts" + ], + "exclude": [ + "../node_modules", + "../dev/lib" + ] +}
\ No newline at end of file diff --git a/test/jsdom.test.js b/test/jsdom.test.js index c53f374e..6c2e00ee 100644 --- a/test/jsdom.test.js +++ b/test/jsdom.test.js @@ -26,20 +26,25 @@ import {expect, test} from 'vitest'; */ function testJSDOMSelectorBug() { test('JSDOMSelectorBug', () => { - // nwsapi is used by JSDOM + // nwsapi is used by JSDOM const dom = new JSDOM(); const {document} = dom.window; const div = document.createElement('div'); div.innerHTML = '<div class="b"><div class="c"></div></div>'; const c = div.querySelector('.c'); - expect(() => c.matches('.a:nth-last-of-type(1) .b .c')).not.toThrow(); + expect(() => { + if (c === null) { throw new Error('Element not found'); } + c.matches('.a:nth-last-of-type(1) .b .c'); + }).not.toThrow(); }); } +/** */ export function testJSDOM() { testJSDOMSelectorBug(); } +/** */ function main() { testJSDOM(); } diff --git a/test/json-schema.test.js b/test/json-schema.test.js index 5370e8da..e534f538 100644 --- a/test/json-schema.test.js +++ b/test/json-schema.test.js @@ -19,25 +19,47 @@ import {expect, test} from 'vitest'; import {JsonSchema} from '../ext/js/data/json-schema.js'; +/** + * @param {import('json-schema').Schema} schema + * @param {unknown} value + * @returns {boolean} + */ function schemaValidate(schema, value) { return new JsonSchema(schema).isValid(value); } +/** + * @param {import('json-schema').Schema} schema + * @param {unknown} value + * @returns {import('json-schema').Value} + */ function getValidValueOrDefault(schema, value) { return new JsonSchema(schema).getValidValueOrDefault(value); } +/** + * @param {import('json-schema').Schema} schema + * @param {import('json-schema').Value} value + * @returns {import('json-schema').Value} + */ function createProxy(schema, value) { return new JsonSchema(schema).createProxy(value); } +/** + * @template T + * @param {T} value + * @returns {T} + */ function clone(value) { return JSON.parse(JSON.stringify(value)); } +/** */ function testValidate1() { test('Validate1', () => { + /** @type {import('json-schema').Schema} */ const schema = { allOf: [ { @@ -56,28 +78,34 @@ function testValidate1() { ] }, { - not: [ - {multipleOf: 20} - ] + not: { + anyOf: [ + {multipleOf: 20} + ] + } } ] }; + /** + * @param {number} value + * @returns {boolean} + */ const jsValidate = (value) => { return ( typeof value === 'number' && - ( - (value >= 10 && value <= 100) || - (value >= -100 && value <= -10) - ) && - ( ( - (value % 3) === 0 || - (value % 5) === 0 + (value >= 10 && value <= 100) || + (value >= -100 && value <= -10) + ) && + ( + ( + (value % 3) === 0 || + (value % 5) === 0 + ) && + (value % 15) !== 0 ) && - (value % 15) !== 0 - ) && - (value % 20) !== 0 + (value % 20) !== 0 ); }; @@ -89,10 +117,12 @@ function testValidate1() { }); } +/** */ function testValidate2() { test('Validate2', () => { + /** @type {{schema: import('json-schema').Schema, inputs: {expected: boolean, value: unknown}[]}[]} */ const data = [ - // String tests + // String tests { schema: { type: 'string' @@ -494,10 +524,12 @@ function testValidate2() { } +/** */ function testGetValidValueOrDefault1() { test('GetValidValueOrDefault1', () => { + /** @type {{schema: import('json-schema').Schema, inputs: [value: unknown, expected: unknown][]}[]} */ const data = [ - // Test value defaulting on objects with additionalProperties=false + // Test value defaulting on objects with additionalProperties=false { schema: { type: 'object', @@ -667,10 +699,10 @@ function testGetValidValueOrDefault1() { type: 'object', required: ['toString'], properties: { - toString: { + toString: /** @type {import('json-schema').SchemaObject} */ ({ type: 'string', default: 'default' - } + }) } }, inputs: [ @@ -850,10 +882,12 @@ function testGetValidValueOrDefault1() { } +/** */ function testProxy1() { test('Proxy1', () => { + /** @type {{schema: import('json-schema').Schema, tests: {error: boolean, value?: import('json-schema').Value, action: (value: import('core').SafeAny) => void}[]}[]} */ const data = [ - // Object tests + // Object tests { schema: { type: 'object', @@ -998,6 +1032,7 @@ function testProxy1() { } +/** */ function main() { testValidate1(); testValidate2(); diff --git a/test/object-property-accessor.test.js b/test/object-property-accessor.test.js index a8730093..4d50b1e9 100644 --- a/test/object-property-accessor.test.js +++ b/test/object-property-accessor.test.js @@ -19,6 +19,9 @@ import {expect, test} from 'vitest'; import {ObjectPropertyAccessor} from '../ext/js/general/object-property-accessor.js'; +/** + * @returns {import('core').UnknownObject} + */ function createTestObject() { return { 0: null, @@ -36,8 +39,10 @@ function createTestObject() { } +/** */ function testGet1() { test('Get1', () => { + /** @type {[pathArray: (string|number)[], getExpected: (object: import('core').SafeAny) => unknown][]} */ const data = [ [[], (object) => object], [['0'], (object) => object['0']], @@ -61,11 +66,13 @@ function testGet1() { }); } +/** */ function testGet2() { test('Get2', () => { const object = createTestObject(); const accessor = new ObjectPropertyAccessor(object); + /** @type {[pathArray: (string|number)[], message: string][]} */ const data = [ [[0], 'Invalid path: [0]'], [['0', 'invalid'], 'Invalid path: ["0"].invalid'], @@ -95,9 +102,11 @@ function testGet2() { } +/** */ function testSet1() { test('Set1', () => { const testValue = {}; + /** @type {(string|number)[][]} */ const data = [ ['0'], ['value1', 'value2'], @@ -120,12 +129,14 @@ function testSet1() { }); } +/** */ function testSet2() { test('Set2', () => { const object = createTestObject(); const accessor = new ObjectPropertyAccessor(object); const testValue = {}; + /** @type {[pathArray: (string|number)[], message: string][]} */ const data = [ [[], 'Invalid path'], [[0], 'Invalid path: [0]'], @@ -148,10 +159,17 @@ function testSet2() { } +/** */ function testDelete1() { test('Delete1', () => { + /** + * @param {unknown} object + * @param {string} property + * @returns {boolean} + */ const hasOwn = (object, property) => Object.prototype.hasOwnProperty.call(object, property); + /** @type {[pathArray: (string|number)[], validate: (object: import('core').SafeAny) => boolean][]} */ const data = [ [['0'], (object) => !hasOwn(object, '0')], [['value1', 'value2'], (object) => !hasOwn(object.value1, 'value2')], @@ -171,8 +189,10 @@ function testDelete1() { }); } +/** */ function testDelete2() { test('Delete2', () => { + /** @type {[pathArray: (string|number)[], message: string][]} */ const data = [ [[], 'Invalid path'], [[0], 'Invalid path: [0]'], @@ -201,8 +221,10 @@ function testDelete2() { } +/** */ function testSwap1() { test('Swap1', () => { + /** @type {[pathArray: (string|number)[], compareValues: boolean][]} */ const data = [ [['0'], true], [['value1', 'value2'], true], @@ -237,8 +259,10 @@ function testSwap1() { }); } +/** */ function testSwap2() { test('Swap2', () => { + /** @type {[pathArray1: (string|number)[], pathArray2: (string|number)[], checkRevert: boolean, message: string][]} */ const data = [ [[], [], false, 'Invalid path 1'], [['0'], [], false, 'Invalid path 2'], @@ -276,8 +300,10 @@ function testSwap2() { } +/** */ function testGetPathString1() { test('GetPathString1', () => { + /** @type {[pathArray: (string|number)[], expected: string][]} */ const data = [ [[], ''], [[0], '[0]'], @@ -298,22 +324,27 @@ function testGetPathString1() { }); } +/** */ function testGetPathString2() { test('GetPathString2', () => { + /** @type {[pathArray: unknown[], message: string][]} */ const data = [ [[1.5], 'Invalid index'], [[null], 'Invalid type: object'] ]; for (const [pathArray, message] of data) { + // @ts-expect-error - Throwing is expected expect(() => ObjectPropertyAccessor.getPathString(pathArray)).toThrow(message); } }); } +/** */ function testGetPathArray1() { test('GetPathArray1', () => { + /** @type {[pathString: string, pathArray: (string|number)[]][]} */ const data = [ ['', []], ['[0]', [0]], @@ -338,8 +369,10 @@ function testGetPathArray1() { }); } +/** */ function testGetPathArray2() { test('GetPathArray2', () => { + /** @type {[pathString: string, message: string][]} */ const data = [ ['?', 'Unexpected character: ?'], ['.', 'Unexpected character: .'], @@ -372,8 +405,10 @@ function testGetPathArray2() { } +/** */ function testHasProperty() { test('HasProperty', () => { + /** @type {[object: unknown, property: unknown, expected: boolean][]} */ const data = [ [{}, 'invalid', false], [{}, 0, false], @@ -389,13 +424,16 @@ function testHasProperty() { ]; for (const [object, property, expected] of data) { + // @ts-expect-error - Ignore potentially property types expect(ObjectPropertyAccessor.hasProperty(object, property)).toStrictEqual(expected); } }); } +/** */ function testIsValidPropertyType() { test('IsValidPropertyType', () => { + /** @type {[object: unknown, property: unknown, expected: boolean][]} */ const data = [ [{}, 'invalid', true], [{}, 0, false], @@ -411,12 +449,14 @@ function testIsValidPropertyType() { ]; for (const [object, property, expected] of data) { + // @ts-expect-error - Ignore potentially property types expect(ObjectPropertyAccessor.isValidPropertyType(object, property)).toStrictEqual(expected); } }); } +/** */ function main() { testGet1(); testGet2(); diff --git a/test/options-util.test.js b/test/options-util.test.js index ff5b6713..7845d759 100644 --- a/test/options-util.test.js +++ b/test/options-util.test.js @@ -24,7 +24,12 @@ import {OptionsUtil} from '../ext/js/data/options-util.js'; import {TemplatePatcher} from '../ext/js/templates/template-patcher.js'; const dirname = path.dirname(fileURLToPath(import.meta.url)); -vi.stubGlobal('fetch', async function fetch(url2) { + +/** + * @param {string} url2 + * @returns {Promise<import('dev/vm').PseudoFetchResponse>} + */ +async function fetch(url2) { const filePath = url.fileURLToPath(url2); await Promise.resolve(); const content = fs.readFileSync(filePath, {encoding: null}); @@ -35,15 +40,22 @@ vi.stubGlobal('fetch', async function fetch(url2) { text: async () => Promise.resolve(content.toString('utf8')), json: async () => Promise.resolve(JSON.parse(content.toString('utf8'))) }; -}); -vi.stubGlobal('chrome', { +} +/** @type {import('dev/vm').PseudoChrome} */ +const chrome = { runtime: { - getURL: (path2) => { + getURL(path2) { return url.pathToFileURL(path.join(dirname, '..', 'ext', path2.replace(/^\//, ''))).href; } } -}); +}; + +vi.stubGlobal('fetch', fetch); +vi.stubGlobal('chrome', chrome); +/** + * @returns {unknown} + */ function createProfileOptionsTestData1() { return { version: 14, @@ -144,6 +156,9 @@ function createProfileOptionsTestData1() { }; } +/** + * @returns {unknown} + */ function createOptionsTestData1() { return { profiles: [ @@ -243,6 +258,9 @@ function createOptionsTestData1() { } +/** + * @returns {unknown} + */ function createProfileOptionsUpdatedTestData1() { return { general: { @@ -519,6 +537,9 @@ function createProfileOptionsUpdatedTestData1() { }; } +/** + * @returns {unknown} + */ function createOptionsUpdatedTestData1() { return { profiles: [ @@ -612,6 +633,7 @@ function createOptionsUpdatedTestData1() { } +/** */ async function testUpdate() { test('Update', async () => { const optionsUtil = new OptionsUtil(); @@ -624,8 +646,10 @@ async function testUpdate() { }); } +/** */ async function testDefault() { test('Default', async () => { + /** @type {((options: import('options-util').IntermediateOptions) => void)[]} */ const data = [ (options) => options, (options) => { @@ -651,12 +675,17 @@ async function testDefault() { }); } +/** */ async function testFieldTemplatesUpdate() { test('FieldTemplatesUpdate', async () => { const optionsUtil = new OptionsUtil(); await optionsUtil.prepare(); const templatePatcher = new TemplatePatcher(); + /** + * @param {string} fileName + * @returns {string} + */ const loadDataFile = (fileName) => { const content = fs.readFileSync(path.join(dirname, '..', 'ext', fileName), {encoding: 'utf8'}); return templatePatcher.parsePatch(content).addition; @@ -671,6 +700,11 @@ async function testFieldTemplatesUpdate() { {version: 13, changes: loadDataFile('data/templates/anki-field-templates-upgrade-v13.handlebars')}, {version: 21, changes: loadDataFile('data/templates/anki-field-templates-upgrade-v21.handlebars')} ]; + /** + * @param {number} startVersion + * @param {number} targetVersion + * @returns {string} + */ const getUpdateAdditions = (startVersion, targetVersion) => { let value = ''; for (const {version, changes} of updates) { @@ -682,7 +716,7 @@ async function testFieldTemplatesUpdate() { }; const data = [ - // Standard format + // Standard format { oldVersion: 0, newVersion: 12, @@ -1564,7 +1598,7 @@ async function testFieldTemplatesUpdate() { const updatesPattern = /<<<UPDATE-ADDITIONS>>>/g; for (const {old, expected, oldVersion, newVersion} of data) { - const options = createOptionsTestData1(); + const options = /** @type {import('core').SafeAny} */ (createOptionsTestData1()); options.profiles[0].options.anki.fieldTemplates = old; options.version = oldVersion; @@ -1578,6 +1612,7 @@ async function testFieldTemplatesUpdate() { } +/** */ async function main() { await testUpdate(); await testDefault(); diff --git a/test/playwright/integration.spec.js b/test/playwright/integration.spec.js index b9a86d84..c8cf2f6d 100644 --- a/test/playwright/integration.spec.js +++ b/test/playwright/integration.spec.js @@ -45,7 +45,8 @@ test('search clipboard', async ({page, extensionId}) => { test('anki add', async ({context, page, extensionId}) => { // mock anki routes - let resolve; + /** @type {?(value: unknown) => void} */ + let resolve = null; const addNotePromise = new Promise((res) => { resolve = res; }); @@ -53,7 +54,7 @@ test('anki add', async ({context, page, extensionId}) => { mockAnkiRouteHandler(route); const req = route.request(); if (req.url().includes('127.0.0.1:8765') && req.postDataJSON().action === 'addNote') { - resolve(req.postDataJSON()); + /** @type {(value: unknown) => void} */ (resolve)(req.postDataJSON()); } }); @@ -63,7 +64,11 @@ test('anki add', async ({context, page, extensionId}) => { // load in test dictionary const dictionary = createDictionaryArchive(path.join(root, 'test/data/dictionaries/valid-dictionary1'), 'valid-dictionary1'); const testDictionarySource = await dictionary.generateAsync({type: 'arraybuffer'}); - await page.locator('input[id="dictionary-import-file-input"]').setInputFiles({name: 'valid-dictionary1.zip', buffer: Buffer.from(testDictionarySource)}); + await page.locator('input[id="dictionary-import-file-input"]').setInputFiles({ + name: 'valid-dictionary1.zip', + mimeType: 'application/x-zip', + buffer: Buffer.from(testDictionarySource) + }); await expect(page.locator('id=dictionaries')).toHaveText('Dictionaries (1 installed, 1 enabled)', {timeout: 5 * 60 * 1000}); // connect to anki @@ -75,7 +80,7 @@ test('anki add', async ({context, page, extensionId}) => { await page.locator('select.anki-card-deck').selectOption('Mock Deck'); await page.locator('select.anki-card-model').selectOption('Mock Model'); for (const modelField of mockModelFieldNames) { - await page.locator(`[data-setting="anki.terms.fields.${modelField}"]`).fill(mockModelFieldsToAnkiValues[modelField]); + await page.locator(`[data-setting="anki.terms.fields.${modelField}"]`).fill(/** @type {string} */ (mockModelFieldsToAnkiValues[modelField])); } await page.locator('#anki-cards-modal > div > div.modal-footer > button:nth-child(2)').click(); await writeToClipboardFromPage(page, '読むの例文'); diff --git a/test/playwright/playwright-util.js b/test/playwright/playwright-util.js index 5ceb92fd..ac68db4d 100644 --- a/test/playwright/playwright-util.js +++ b/test/playwright/playwright-util.js @@ -55,6 +55,7 @@ export const mockModelFieldNames = [ 'Sentence' ]; +/** @type {{[key: string]: string|undefined}} */ export const mockModelFieldsToAnkiValues = { 'Word': '{expression}', 'Reading': '{furigana-plain}', @@ -62,6 +63,10 @@ export const mockModelFieldsToAnkiValues = { 'Audio': '{audio}' }; +/** + * @param {import('playwright').Route} route + * @returns {Promise<void>|undefined} + */ export const mockAnkiRouteHandler = (route) => { const reqBody = route.request().postDataJSON(); const respBody = ankiRouteResponses[reqBody.action]; @@ -71,6 +76,11 @@ export const mockAnkiRouteHandler = (route) => { route.fulfill(respBody); }; +/** + * @param {import('playwright').Page} page + * @param {string} text + * @returns {Promise<void>} + */ export const writeToClipboardFromPage = async (page, text) => { await page.evaluate(`navigator.clipboard.writeText('${text}')`); }; @@ -100,6 +110,7 @@ const baseAnkiResp = { contentType: 'text/json' }; +/** @type {{[key: string]: import('core').SerializableObject}} */ const ankiRouteResponses = { 'version': Object.assign({body: JSON.stringify(6)}, baseAnkiResp), 'deckNames': Object.assign({body: JSON.stringify(['Mock Deck'])}, baseAnkiResp), diff --git a/test/playwright/visual.spec.js b/test/playwright/visual.spec.js index 2f46990f..8b48b7c0 100644 --- a/test/playwright/visual.spec.js +++ b/test/playwright/visual.spec.js @@ -48,10 +48,16 @@ test('visual', async ({page, extensionId}) => { // take a screenshot of the settings page with jmdict loaded await expect.soft(page).toHaveScreenshot('settings-jmdict-loaded.png', {mask: [storage_locator]}); + /** + * @param {number} doc_number + * @param {number} test_number + * @param {import('@playwright/test').ElementHandle<Node>} el + * @param {{x: number, y: number}} offset + */ const screenshot = async (doc_number, test_number, el, offset) => { const test_name = 'doc' + doc_number + '-test' + test_number; - const box = await el.boundingBox(); + const box = (await el.boundingBox()) || {x: 0, y: 0, width: 0, height: 0}; // find the popup frame if it exists let popup_frame = page.frames().find((f) => f.url().includes('popup.html')); @@ -66,7 +72,7 @@ test('visual', async ({page, extensionId}) => { popup_frame = await frame_attached; // wait for popup to be attached } try { - await (await popup_frame.frameElement()).waitForElementState('visible', {timeout: 500}); // some tests don't have a popup, so don't fail if it's not there; TODO: check if the popup is expected to be there + await (await /** @type {import('@playwright/test').Frame} */ (popup_frame).frameElement()).waitForElementState('visible', {timeout: 500}); // some tests don't have a popup, so don't fail if it's not there; TODO: check if the popup is expected to be there } catch (error) { console.log(test_name + ' has no popup'); } @@ -75,7 +81,7 @@ test('visual', async ({page, extensionId}) => { await expect.soft(page).toHaveScreenshot(test_name + '.png'); await page.mouse.click(0, 0); // click away so popup disappears - await (await popup_frame.frameElement()).waitForElementState('hidden'); // wait for popup to disappear + await (await /** @type {import('@playwright/test').Frame} */ (popup_frame).frameElement()).waitForElementState('hidden'); // wait for popup to disappear }; // Load test-document1.html diff --git a/test/profile-conditions-util.test.js b/test/profile-conditions-util.test.js index ca8b00ef..62b21555 100644 --- a/test/profile-conditions-util.test.js +++ b/test/profile-conditions-util.test.js @@ -19,31 +19,33 @@ import {expect, test} from 'vitest'; import {ProfileConditionsUtil} from '../ext/js/background/profile-conditions-util.js'; +/** */ function testNormalizeContext() { test('NormalizeContext', () => { + /** @type {{context: import('settings').OptionsContext, expected: import('profile-conditions-util').NormalizedOptionsContext}[]} */ const data = [ - // Empty + // Empty { - context: {}, - expected: {flags: []} + context: {index: 0}, + expected: {index: 0, flags: []} }, // Domain normalization { - context: {url: ''}, - expected: {url: '', flags: []} + context: {depth: 0, url: ''}, + expected: {depth: 0, url: '', flags: []} }, { - context: {url: 'http://example.com/'}, - expected: {url: 'http://example.com/', domain: 'example.com', flags: []} + context: {depth: 0, url: 'http://example.com/'}, + expected: {depth: 0, url: 'http://example.com/', domain: 'example.com', flags: []} }, { - context: {url: 'http://example.com:1234/'}, - expected: {url: 'http://example.com:1234/', domain: 'example.com', flags: []} + context: {depth: 0, url: 'http://example.com:1234/'}, + expected: {depth: 0, url: 'http://example.com:1234/', domain: 'example.com', flags: []} }, { - context: {url: 'http://user@example.com:1234/'}, - expected: {url: 'http://user@example.com:1234/', domain: 'example.com', flags: []} + context: {depth: 0, url: 'http://user@example.com:1234/'}, + expected: {depth: 0, url: 'http://user@example.com:1234/', domain: 'example.com', flags: []} } ]; @@ -55,15 +57,17 @@ function testNormalizeContext() { }); } +/** */ function testSchemas() { test('Schemas', () => { + /** @type {{conditionGroups: import('settings').ProfileConditionGroup[], expectedSchema?: import('json-schema').Schema, inputs?: {expected: boolean, context: import('settings').OptionsContext}[]}[]} */ const data = [ - // Empty + // Empty { conditionGroups: [], expectedSchema: {}, inputs: [ - {expected: true, context: {url: 'http://example.com/'}} + {expected: true, context: {depth: 0, url: 'http://example.com/'}} ] }, { @@ -72,7 +76,7 @@ function testSchemas() { ], expectedSchema: {}, inputs: [ - {expected: true, context: {url: 'http://example.com/'}} + {expected: true, context: {depth: 0, url: 'http://example.com/'}} ] }, { @@ -82,7 +86,7 @@ function testSchemas() { ], expectedSchema: {}, inputs: [ - {expected: true, context: {url: 'http://example.com/'}} + {expected: true, context: {depth: 0, url: 'http://example.com/'}} ] }, @@ -124,14 +128,16 @@ function testSchemas() { } ], expectedSchema: { - not: [ - { - properties: { - depth: {const: 0} - }, - required: ['depth'] - } - ] + not: { + anyOf: [ + { + properties: { + depth: {const: 0} + }, + required: ['depth'] + } + ] + } }, inputs: [ {expected: false, context: {depth: 0, url: 'http://example.com/'}}, @@ -371,9 +377,9 @@ function testSchemas() { }, inputs: [ {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}}, - {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}}, - {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}}, - {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}} + {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt']}}, + {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift']}}, + {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift', 'ctrl']}} ] }, { @@ -383,7 +389,7 @@ function testSchemas() { { type: 'modifierKeys', operator: 'are', - value: 'Alt, Shift' + value: 'alt, shift' } ] } @@ -395,8 +401,8 @@ function testSchemas() { maxItems: 2, minItems: 2, allOf: [ - {contains: {const: 'Alt'}}, - {contains: {const: 'Shift'}} + {contains: {const: 'alt'}}, + {contains: {const: 'shift'}} ] } }, @@ -404,9 +410,9 @@ function testSchemas() { }, inputs: [ {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}}, - {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}}, - {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}} + {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt']}}, + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift']}}, + {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift', 'ctrl']}} ] }, { @@ -422,24 +428,26 @@ function testSchemas() { } ], expectedSchema: { - not: [ - { - properties: { - modifierKeys: { - type: 'array', - maxItems: 0, - minItems: 0 - } - }, - required: ['modifierKeys'] - } - ] + not: { + anyOf: [ + { + properties: { + modifierKeys: { + type: 'array', + maxItems: 0, + minItems: 0 + } + }, + required: ['modifierKeys'] + } + ] + } }, inputs: [ {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}} + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt']}}, + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift']}}, + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift', 'ctrl']}} ] }, { @@ -449,34 +457,36 @@ function testSchemas() { { type: 'modifierKeys', operator: 'areNot', - value: 'Alt, Shift' + value: 'alt, shift' } ] } ], expectedSchema: { - not: [ - { - properties: { - modifierKeys: { - type: 'array', - maxItems: 2, - minItems: 2, - allOf: [ - {contains: {const: 'Alt'}}, - {contains: {const: 'Shift'}} - ] - } - }, - required: ['modifierKeys'] - } - ] + not: { + anyOf: [ + { + properties: { + modifierKeys: { + type: 'array', + maxItems: 2, + minItems: 2, + allOf: [ + {contains: {const: 'alt'}}, + {contains: {const: 'shift'}} + ] + } + }, + required: ['modifierKeys'] + } + ] + } }, inputs: [ {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}}, - {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}} + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt']}}, + {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift']}}, + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift', 'ctrl']}} ] }, { @@ -502,9 +512,9 @@ function testSchemas() { }, inputs: [ {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}} + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt']}}, + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift']}}, + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift', 'ctrl']}} ] }, { @@ -514,7 +524,7 @@ function testSchemas() { { type: 'modifierKeys', operator: 'include', - value: 'Alt, Shift' + value: 'alt, shift' } ] } @@ -525,8 +535,8 @@ function testSchemas() { type: 'array', minItems: 2, allOf: [ - {contains: {const: 'Alt'}}, - {contains: {const: 'Shift'}} + {contains: {const: 'alt'}}, + {contains: {const: 'shift'}} ] } }, @@ -534,9 +544,9 @@ function testSchemas() { }, inputs: [ {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}}, - {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}} + {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt']}}, + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift']}}, + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift', 'ctrl']}} ] }, { @@ -561,9 +571,9 @@ function testSchemas() { }, inputs: [ {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}}, - {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}} + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt']}}, + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift']}}, + {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift', 'ctrl']}} ] }, { @@ -573,7 +583,7 @@ function testSchemas() { { type: 'modifierKeys', operator: 'notInclude', - value: 'Alt, Shift' + value: 'alt, shift' } ] } @@ -582,19 +592,21 @@ function testSchemas() { properties: { modifierKeys: { type: 'array', - not: [ - {contains: {const: 'Alt'}}, - {contains: {const: 'Shift'}} - ] + not: { + anyOf: [ + {contains: {const: 'alt'}}, + {contains: {const: 'shift'}} + ] + } } }, required: ['modifierKeys'] }, inputs: [ {expected: true, context: {depth: 0, url: 'http://example.com/', modifierKeys: []}}, - {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt']}}, - {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift']}}, - {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['Alt', 'Shift', 'Ctrl']}} + {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt']}}, + {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift']}}, + {expected: false, context: {depth: 0, url: 'http://example.com/', modifierKeys: ['alt', 'shift', 'ctrl']}} ] }, @@ -622,11 +634,13 @@ function testSchemas() { } }, inputs: [ - {expected: true, context: {}}, - {expected: true, context: {flags: []}}, - {expected: false, context: {flags: ['test1']}}, - {expected: false, context: {flags: ['test1', 'test2']}}, - {expected: false, context: {flags: ['test1', 'test2', 'test3']}} + {expected: true, context: {depth: 0, url: ''}}, + {expected: true, context: {depth: 0, url: '', flags: []}}, + {expected: false, context: {depth: 0, url: '', flags: ['clipboard']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: false, context: {depth: 0, url: '', flags: ['clipboard', 'test2']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: false, context: {depth: 0, url: '', flags: ['clipboard', 'test2', 'test3']}} ] }, { @@ -636,7 +650,7 @@ function testSchemas() { { type: 'flags', operator: 'are', - value: 'test1, test2' + value: 'clipboard, test2' } ] } @@ -649,18 +663,20 @@ function testSchemas() { maxItems: 2, minItems: 2, allOf: [ - {contains: {const: 'test1'}}, + {contains: {const: 'clipboard'}}, {contains: {const: 'test2'}} ] } } }, inputs: [ - {expected: false, context: {}}, - {expected: false, context: {flags: []}}, - {expected: false, context: {flags: ['test1']}}, - {expected: true, context: {flags: ['test1', 'test2']}}, - {expected: false, context: {flags: ['test1', 'test2', 'test3']}} + {expected: false, context: {depth: 0, url: ''}}, + {expected: false, context: {depth: 0, url: '', flags: []}}, + {expected: false, context: {depth: 0, url: '', flags: ['clipboard']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: true, context: {depth: 0, url: '', flags: ['clipboard', 'test2']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: false, context: {depth: 0, url: '', flags: ['clipboard', 'test2', 'test3']}} ] }, { @@ -676,25 +692,29 @@ function testSchemas() { } ], expectedSchema: { - not: [ - { - required: ['flags'], - properties: { - flags: { - type: 'array', - maxItems: 0, - minItems: 0 + not: { + anyOf: [ + { + required: ['flags'], + properties: { + flags: { + type: 'array', + maxItems: 0, + minItems: 0 + } } } - } - ] + ] + } }, inputs: [ - {expected: false, context: {}}, - {expected: false, context: {flags: []}}, - {expected: true, context: {flags: ['test1']}}, - {expected: true, context: {flags: ['test1', 'test2']}}, - {expected: true, context: {flags: ['test1', 'test2', 'test3']}} + {expected: false, context: {depth: 0, url: ''}}, + {expected: false, context: {depth: 0, url: '', flags: []}}, + {expected: true, context: {depth: 0, url: '', flags: ['clipboard']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: true, context: {depth: 0, url: '', flags: ['clipboard', 'test2']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: true, context: {depth: 0, url: '', flags: ['clipboard', 'test2', 'test3']}} ] }, { @@ -704,35 +724,39 @@ function testSchemas() { { type: 'flags', operator: 'areNot', - value: 'test1, test2' + value: 'clipboard, test2' } ] } ], expectedSchema: { - not: [ - { - required: ['flags'], - properties: { - flags: { - type: 'array', - maxItems: 2, - minItems: 2, - allOf: [ - {contains: {const: 'test1'}}, - {contains: {const: 'test2'}} - ] + not: { + anyOf: [ + { + required: ['flags'], + properties: { + flags: { + type: 'array', + maxItems: 2, + minItems: 2, + allOf: [ + {contains: {const: 'clipboard'}}, + {contains: {const: 'test2'}} + ] + } } } - } - ] + ] + } }, inputs: [ - {expected: true, context: {}}, - {expected: true, context: {flags: []}}, - {expected: true, context: {flags: ['test1']}}, - {expected: false, context: {flags: ['test1', 'test2']}}, - {expected: true, context: {flags: ['test1', 'test2', 'test3']}} + {expected: true, context: {depth: 0, url: ''}}, + {expected: true, context: {depth: 0, url: '', flags: []}}, + {expected: true, context: {depth: 0, url: '', flags: ['clipboard']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: false, context: {depth: 0, url: '', flags: ['clipboard', 'test2']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: true, context: {depth: 0, url: '', flags: ['clipboard', 'test2', 'test3']}} ] }, { @@ -757,11 +781,13 @@ function testSchemas() { } }, inputs: [ - {expected: true, context: {}}, - {expected: true, context: {flags: []}}, - {expected: true, context: {flags: ['test1']}}, - {expected: true, context: {flags: ['test1', 'test2']}}, - {expected: true, context: {flags: ['test1', 'test2', 'test3']}} + {expected: true, context: {depth: 0, url: ''}}, + {expected: true, context: {depth: 0, url: '', flags: []}}, + {expected: true, context: {depth: 0, url: '', flags: ['clipboard']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: true, context: {depth: 0, url: '', flags: ['clipboard', 'test2']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: true, context: {depth: 0, url: '', flags: ['clipboard', 'test2', 'test3']}} ] }, { @@ -771,7 +797,7 @@ function testSchemas() { { type: 'flags', operator: 'include', - value: 'test1, test2' + value: 'clipboard, test2' } ] } @@ -783,18 +809,20 @@ function testSchemas() { type: 'array', minItems: 2, allOf: [ - {contains: {const: 'test1'}}, + {contains: {const: 'clipboard'}}, {contains: {const: 'test2'}} ] } } }, inputs: [ - {expected: false, context: {}}, - {expected: false, context: {flags: []}}, - {expected: false, context: {flags: ['test1']}}, - {expected: true, context: {flags: ['test1', 'test2']}}, - {expected: true, context: {flags: ['test1', 'test2', 'test3']}} + {expected: false, context: {depth: 0, url: ''}}, + {expected: false, context: {depth: 0, url: '', flags: []}}, + {expected: false, context: {depth: 0, url: '', flags: ['clipboard']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: true, context: {depth: 0, url: '', flags: ['clipboard', 'test2']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: true, context: {depth: 0, url: '', flags: ['clipboard', 'test2', 'test3']}} ] }, { @@ -818,11 +846,13 @@ function testSchemas() { } }, inputs: [ - {expected: true, context: {}}, - {expected: true, context: {flags: []}}, - {expected: true, context: {flags: ['test1']}}, - {expected: true, context: {flags: ['test1', 'test2']}}, - {expected: true, context: {flags: ['test1', 'test2', 'test3']}} + {expected: true, context: {depth: 0, url: ''}}, + {expected: true, context: {depth: 0, url: '', flags: []}}, + {expected: true, context: {depth: 0, url: '', flags: ['clipboard']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: true, context: {depth: 0, url: '', flags: ['clipboard', 'test2']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: true, context: {depth: 0, url: '', flags: ['clipboard', 'test2', 'test3']}} ] }, { @@ -832,7 +862,7 @@ function testSchemas() { { type: 'flags', operator: 'notInclude', - value: 'test1, test2' + value: 'clipboard, test2' } ] } @@ -842,19 +872,23 @@ function testSchemas() { properties: { flags: { type: 'array', - not: [ - {contains: {const: 'test1'}}, - {contains: {const: 'test2'}} - ] + not: { + anyOf: [ + {contains: {const: 'clipboard'}}, + {contains: {const: 'test2'}} + ] + } } } }, inputs: [ - {expected: true, context: {}}, - {expected: true, context: {flags: []}}, - {expected: false, context: {flags: ['test1']}}, - {expected: false, context: {flags: ['test1', 'test2']}}, - {expected: false, context: {flags: ['test1', 'test2', 'test3']}} + {expected: true, context: {depth: 0, url: ''}}, + {expected: true, context: {depth: 0, url: '', flags: []}}, + {expected: false, context: {depth: 0, url: '', flags: ['clipboard']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: false, context: {depth: 0, url: '', flags: ['clipboard', 'test2']}}, + // @ts-expect-error - Ignore type for string flag for testing purposes + {expected: false, context: {depth: 0, url: '', flags: ['clipboard', 'test2', 'test3']}} ] }, @@ -1082,6 +1116,7 @@ function testSchemas() { } +/** */ function main() { testNormalizeContext(); testSchemas(); diff --git a/test/text-source-map.test.js b/test/text-source-map.test.js index aeaba000..54b39319 100644 --- a/test/text-source-map.test.js +++ b/test/text-source-map.test.js @@ -19,6 +19,7 @@ import {expect, test} from 'vitest'; import {TextSourceMap} from '../ext/js/general/text-source-map.js'; +/** */ function testSource() { test('Source', () => { const data = [ @@ -34,8 +35,10 @@ function testSource() { }); } +/** */ function testEquals() { test('Equals', () => { + /** @type {[args1: [source1: string, mapping1: ?(number[])], args2: [source2: string, mapping2: ?(number[])], expectedEquals: boolean][]} */ const data = [ [['source1', null], ['source1', null], true], [['source2', null], ['source2', null], true], @@ -76,8 +79,10 @@ function testEquals() { }); } +/** */ function testGetSourceLength() { test('GetSourceLength', () => { + /** @type {[args: [source: string, mapping: number[]], finalLength: number, expectedValue: number][]} */ const data = [ [['source', [1, 1, 1, 1, 1, 1]], 1, 1], [['source', [1, 1, 1, 1, 1, 1]], 2, 2], @@ -103,10 +108,12 @@ function testGetSourceLength() { }); } +/** */ function testCombineInsert() { test('CombineInsert', () => { + /** @type {[args: [source: string, mapping: ?(number[])], expectedArgs: [expectedSource: string, expectedMapping: ?(number[])], operations: [operation: string, arg1: number, arg2: number][]][]} */ const data = [ - // No operations + // No operations [ ['source', null], ['source', [1, 1, 1, 1, 1, 1]], @@ -226,6 +233,7 @@ function testCombineInsert() { } +/** */ function main() { testSource(); testEquals(); diff --git a/test/translator.test.js b/test/translator.test.js index 7a827d39..3db560a7 100644 --- a/test/translator.test.js +++ b/test/translator.test.js @@ -28,6 +28,7 @@ vi.stubGlobal('IDBKeyRange', IDBKeyRange); const dirname = path.dirname(fileURLToPath(import.meta.url)); +/** */ async function main() { const translatorVM = new TranslatorVM(); const dictionaryDirectory = path.join(dirname, 'data', 'dictionaries', 'valid-dictionary1'); @@ -53,6 +54,7 @@ async function main() { case 'findTerms': { const {name, mode, text} = t; + /** @type {import('translation').FindTermsOptions} */ const options = translatorVM.buildOptions(optionsPresets, t.options); const {dictionaryEntries, originalTextLength} = structuredClone(await translatorVM.translator.findTerms(mode, text, options)); const noteDataList = mode !== 'simple' ? structuredClone(dictionaryEntries.map((dictionaryEntry) => translatorVM.createTestAnkiNoteData(structuredClone(dictionaryEntry), mode))) : null; @@ -66,9 +68,10 @@ async function main() { case 'findKanji': { const {name, text} = t; + /** @type {import('translation').FindKanjiOptions} */ const options = translatorVM.buildOptions(optionsPresets, t.options); const dictionaryEntries = structuredClone(await translatorVM.translator.findKanji(text, options)); - const noteDataList = structuredClone(dictionaryEntries.map((dictionaryEntry) => translatorVM.createTestAnkiNoteData(structuredClone(dictionaryEntry), null))); + const noteDataList = structuredClone(dictionaryEntries.map((dictionaryEntry) => translatorVM.createTestAnkiNoteData(structuredClone(dictionaryEntry), 'split'))); actualResults1.push({name, dictionaryEntries}); actualResults2.push({name, noteDataList}); expect(dictionaryEntries).toStrictEqual(expected1.dictionaryEntries); |