diff options
26 files changed, 131 insertions, 55 deletions
| diff --git a/.eslintrc.json b/.eslintrc.json index e347c978..51bb2328 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -398,7 +398,7 @@                  "@typescript-eslint/no-misused-promises": "off",                  "@typescript-eslint/no-redundant-type-constituents": "error",                  "@typescript-eslint/no-unsafe-argument": "error", -                "@typescript-eslint/no-unsafe-assignment": "off", +                "@typescript-eslint/no-unsafe-assignment": "error",                  "@typescript-eslint/no-unsafe-call": "off",                  "@typescript-eslint/no-unsafe-enum-comparison": "off",                  "@typescript-eslint/no-unsafe-member-access": "off", diff --git a/dev/dictionary-validate.js b/dev/dictionary-validate.js index b770f311..3c7cf30b 100644 --- a/dev/dictionary-validate.js +++ b/dev/dictionary-validate.js @@ -80,6 +80,7 @@ async function validateDictionaryBanks(mode, entries, schemasDetails) {  export async function validateDictionary(mode, archiveData, schemas) {      const entries = await getDictionaryArchiveEntries(archiveData);      const indexFileName = getIndexFileName(); +    /** @type {import('dictionary-data').Index} */      const index = await getDictionaryArchiveJson(entries, indexFileName);      const version = index.format || index.version; diff --git a/ext/js/accessibility/google-docs-xray.js b/ext/js/accessibility/google-docs-xray.js index 15e1d50b..6723a468 100644 --- a/ext/js/accessibility/google-docs-xray.js +++ b/ext/js/accessibility/google-docs-xray.js @@ -17,7 +17,7 @@  /** Entry point. */  function main() { -    /** @type {Window} */ +    /** @type {unknown} */      // @ts-expect-error - Firefox Xray vision      const window2 = window.wrappedJSObject;      if (!(typeof window2 === 'object' && window2 !== null)) { return; } diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js index 294c11db..d042a253 100644 --- a/ext/js/background/backend.js +++ b/ext/js/background/backend.js @@ -1831,16 +1831,7 @@ export class Backend {          }          try { -            const tabWindow = await new Promise((resolve, reject) => { -                chrome.windows.get(tab.windowId, {}, (value) => { -                    const e = chrome.runtime.lastError; -                    if (e) { -                        reject(new Error(e.message)); -                    } else { -                        resolve(value); -                    } -                }); -            }); +            const tabWindow = await this._getWindow(tab.windowId);              if (!tabWindow.focused) {                  await /** @type {Promise<void>} */ (new Promise((resolve, reject) => {                      chrome.windows.update(tab.windowId, {focused: true}, () => { @@ -1859,6 +1850,23 @@ export class Backend {      }      /** +     * @param {number} windowId +     * @returns {Promise<chrome.windows.Window>} +     */ +    _getWindow(windowId) { +        return new Promise((resolve, reject) => { +            chrome.windows.get(windowId, {}, (value) => { +                const e = chrome.runtime.lastError; +                if (e) { +                    reject(new Error(e.message)); +                } else { +                    resolve(value); +                } +            }); +        }); +    } + +    /**       * @param {number} tabId       * @param {number} frameId       * @param {?number} [timeout=null] @@ -2208,6 +2216,7 @@ export class Backend {      async _injectAnkiNoteDictionaryMedia(ankiConnect, timestamp, dictionaryMediaDetails) {          const targets = [];          const detailsList = []; +        /** @type {Map<string, {dictionary: string, path: string, media: ?import('dictionary-database').MediaDataStringContent}>} */          const detailsMap = new Map();          for (const {dictionary, path} of dictionaryMediaDetails) {              const target = {dictionary, path}; diff --git a/ext/js/background/offscreen-proxy.js b/ext/js/background/offscreen-proxy.js index e65ec65e..9e7b5b74 100644 --- a/ext/js/background/offscreen-proxy.js +++ b/ext/js/background/offscreen-proxy.js @@ -88,6 +88,7 @@ export class OffscreenProxy {          if (!chrome.runtime.getContexts) { // Chrome version below 116              // Clients: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/clients              // @ts-expect-error - Types not set up for service workers yet +            // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment              const matchedClients = await clients.matchAll();              // @ts-expect-error - Types not set up for service workers yet              return await matchedClients.some((client) => client.url === offscreenUrl); diff --git a/ext/js/background/script-manager.js b/ext/js/background/script-manager.js index 84213452..ea1702e9 100644 --- a/ext/js/background/script-manager.js +++ b/ext/js/background/script-manager.js @@ -60,16 +60,7 @@ export function injectStylesheet(type, content, tabId, frameId, allFrames) {   * @returns {Promise<boolean>} `true` if a script is registered, `false` otherwise.   */  export async function isContentScriptRegistered(id) { -    const scripts = await new Promise((resolve, reject) => { -        chrome.scripting.getRegisteredContentScripts({ids: [id]}, (result) => { -            const e = chrome.runtime.lastError; -            if (e) { -                reject(new Error(e.message)); -            } else { -                resolve(result); -            } -        }); -    }); +    const scripts = await getRegisteredContentScripts([id]);      for (const script of scripts) {          if (script.id === id) {              return true; @@ -155,3 +146,20 @@ function createContentScriptRegistrationOptions(details, id) {      }      return options;  } + +/** + * @param {string[]} ids + * @returns {Promise<chrome.scripting.RegisteredContentScript[]>} + */ +function getRegisteredContentScripts(ids) { +    return new Promise((resolve, reject) => { +        chrome.scripting.getRegisteredContentScripts({ids}, (result) => { +            const e = chrome.runtime.lastError; +            if (e) { +                reject(new Error(e.message)); +            } else { +                resolve(result); +            } +        }); +    }); +} diff --git a/ext/js/comm/anki-connect.js b/ext/js/comm/anki-connect.js index 6a008f40..23183e79 100644 --- a/ext/js/comm/anki-connect.js +++ b/ext/js/comm/anki-connect.js @@ -18,6 +18,7 @@  import {ExtensionError} from '../core/extension-error.js';  import {parseJson} from '../core/json.js'; +import {isObjectNotArray} from '../core/object-utilities.js';  import {getRootDeckName} from '../data/anki-util.js';  /** @@ -606,15 +607,15 @@ export class AnkiConnect {              if (typeof modelName !== 'string') {                  throw this._createError(`Unexpected result type at index ${i}, field modelName: expected string, received ${this._getTypeName(modelName)}`, result);              } -            if (typeof fields !== 'object' || fields === null) { -                throw this._createError(`Unexpected result type at index ${i}, field fields: expected string, received ${this._getTypeName(fields)}`, result); +            if (!isObjectNotArray(fields)) { +                throw this._createError(`Unexpected result type at index ${i}, field fields: expected object, received ${this._getTypeName(fields)}`, result);              }              const tags2 = /** @type {string[]} */ (this._normalizeArray(tags, -1, 'string', ', field tags'));              const cards2 = /** @type {number[]} */ (this._normalizeArray(cards, -1, 'number', ', field cards'));              /** @type {{[key: string]: import('anki').NoteFieldInfo}} */              const fields2 = {};              for (const [key, fieldInfo] of Object.entries(fields)) { -                if (typeof fieldInfo !== 'object' || fieldInfo === null) { continue; } +                if (!isObjectNotArray(fieldInfo)) { continue; }                  const {value, order} = fieldInfo;                  if (typeof value !== 'string' || typeof order !== 'number') { continue; }                  fields2[key] = {value, order}; diff --git a/ext/js/comm/frame-ancestry-handler.js b/ext/js/comm/frame-ancestry-handler.js index 39288738..1915f121 100644 --- a/ext/js/comm/frame-ancestry-handler.js +++ b/ext/js/comm/frame-ancestry-handler.js @@ -288,6 +288,7 @@ export class FrameAncestryHandler {                  }                  /** @type {?ShadowRoot|undefined} */ +                // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment                  const shadowRoot = (                      element.shadowRoot ||                      // @ts-expect-error - openOrClosedShadowRoot is available to Firefox 63+ for WebExtensions diff --git a/ext/js/comm/frame-client.js b/ext/js/comm/frame-client.js index a30efa29..effd3e7c 100644 --- a/ext/js/comm/frame-client.js +++ b/ext/js/comm/frame-client.js @@ -83,6 +83,7 @@ export class FrameClient {       */      _connectInternal(frame, targetOrigin, hostFrameId, setupFrame, timeout) {          return new Promise((resolve, reject) => { +            /** @type {Map<string, string>} */              const tokenMap = new Map();              /** @type {?import('core').Timeout} */              let timer = null; diff --git a/ext/js/data/anki-note-builder.js b/ext/js/data/anki-note-builder.js index 6a6a6177..aec8cdd9 100644 --- a/ext/js/data/anki-note-builder.js +++ b/ext/js/data/anki-note-builder.js @@ -88,6 +88,7 @@ export class AnkiNoteBuilder {          }          const formattedFieldValues = await Promise.all(formattedFieldValuePromises); +        /** @type {Map<string, import('anki-note-builder').Requirement>} */          const uniqueRequirements = new Map();          /** @type {import('anki').NoteFields} */          const noteFields = {}; diff --git a/ext/js/data/database.js b/ext/js/data/database.js index 7f37347b..a53c8ddb 100644 --- a/ext/js/data/database.js +++ b/ext/js/data/database.js @@ -194,10 +194,10 @@ export class Database {          request.onsuccess = (e) => {              const cursor = /** @type {IDBRequest<?IDBCursorWithValue>} */ (e.target).result;              if (cursor) { -                /** @type {TResult} */ +                /** @type {unknown} */                  const value = cursor.value; -                if (noPredicate || predicate(value, predicateArg)) { -                    resolve(value, data); +                if (noPredicate || predicate(/** @type {TResult} */ (value), predicateArg)) { +                    resolve(/** @type {TResult} */ (value), data);                  } else {                      cursor.continue();                  } @@ -424,9 +424,9 @@ export class Database {          request.onsuccess = (e) => {              const cursor = /** @type {IDBRequest<?IDBCursorWithValue>} */ (e.target).result;              if (cursor) { -                /** @type {TResult} */ +                /** @type {unknown} */                  const value = cursor.value; -                results.push(value); +                results.push(/** @type {TResult} */ (value));                  cursor.continue();              } else {                  onSuccess(results, data); diff --git a/ext/js/data/json-schema.js b/ext/js/data/json-schema.js index 9e1497e9..0a2b8d82 100644 --- a/ext/js/data/json-schema.js +++ b/ext/js/data/json-schema.js @@ -1263,7 +1263,7 @@ class JsonSchemaProxyHandler {      /**       * @param {import('ext/json-schema').ValueObjectOrArray} target       * @param {string|number|symbol} property -     * @param {import('core').SafeAny} value +     * @param {unknown} value       * @returns {boolean}       * @throws {Error}       */ diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index b6fb6686..ba404bc2 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -27,6 +27,7 @@ import {JsonSchema} from './json-schema.js';  // of the options object to a newer format. SafeAny is used for much of this, since every single  // legacy format does not contain type definitions.  /* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */  export class OptionsUtil {      constructor() { @@ -1295,4 +1296,5 @@ export class OptionsUtil {      }  } +/* eslint-enable @typescript-eslint/no-unsafe-assignment */  /* eslint-enable @typescript-eslint/no-unsafe-argument */ diff --git a/ext/js/dictionary/dictionary-data-util.js b/ext/js/dictionary/dictionary-data-util.js index a90668f4..dfdd5601 100644 --- a/ext/js/dictionary/dictionary-data-util.js +++ b/ext/js/dictionary/dictionary-data-util.js @@ -24,6 +24,7 @@ export function groupTermTags(dictionaryEntry) {      const {headwords} = dictionaryEntry;      const headwordCount = headwords.length;      const uniqueCheck = (headwordCount > 1); +    /** @type {Map<string, number>} */      const resultsIndexMap = new Map();      const results = [];      for (let i = 0; i < headwordCount; ++i) { diff --git a/ext/js/display/display-history.js b/ext/js/display/display-history.js index 183368d0..0806e17b 100644 --- a/ext/js/display/display-history.js +++ b/ext/js/display/display-history.js @@ -37,6 +37,7 @@ export class DisplayHistory extends EventDispatcher {          /** @type {Map<string, import('display-history').Entry>} */          this._historyMap = new Map(); +        /** @type {unknown} */          const historyState = history.state;          const {id, state} = (              isObjectNotArray(historyState) ? @@ -188,6 +189,7 @@ export class DisplayHistory extends EventDispatcher {      /** */      _updateStateFromHistory() { +        /** @type {unknown} */          let state = history.state;          let id = null;          if (isObjectNotArray(state)) { @@ -208,7 +210,7 @@ export class DisplayHistory extends EventDispatcher {          // Fallback          this._current.id = (typeof id === 'string' ? id : this._generateId()); -        this._current.state = state; +        this._current.state = /** @type {import('display-history').EntryState} */ (state);          this._current.content = null;          this._clear();      } diff --git a/ext/js/input/hotkey-help-controller.js b/ext/js/input/hotkey-help-controller.js index b495365d..f85735fc 100644 --- a/ext/js/input/hotkey-help-controller.js +++ b/ext/js/input/hotkey-help-controller.js @@ -67,9 +67,10 @@ export class HotkeyHelpController {              const hotkey = (global ? this._globalActionHotkeys : this._localActionHotkeys).get(action);              for (let i = 0, ii = attributes.length; i < ii; ++i) {                  const attribute = attributes[i]; +                /** @type {unknown} */                  let value;                  if (typeof hotkey !== 'undefined') { -                    value = /** @type {unknown} */ (multipleValues ? values[i] : values); +                    value = multipleValues ? values[i] : values;                      if (typeof value === 'string') {                          value = value.replace(replacementPattern, hotkey);                      } @@ -158,7 +159,8 @@ export class HotkeyHelpController {          if (typeof hotkey !== 'string') { return null; }          const data = /** @type {unknown} */ (parseJson(hotkey));          if (!Array.isArray(data)) { return null; } -        const [action, attributes, values] = /** @type {unknown[]} */ (data); +        const dataArray = /** @type {unknown[]} */ (data); +        const [action, attributes, values] = dataArray;          if (typeof action !== 'string') { return null; }          /** @type {string[]} */          const attributesArray = []; diff --git a/ext/js/language/translator.js b/ext/js/language/translator.js index 845d53d5..0d26b2f0 100644 --- a/ext/js/language/translator.js +++ b/ext/js/language/translator.js @@ -289,6 +289,7 @@ export class Translator {              return false;          } +        /** @type {Map<string, number>} */          const frequencyCounter = new Map();          for (const element of array1) { @@ -400,6 +401,7 @@ export class Translator {       * @returns {Map<string, import('translation-internal').DatabaseDeinflection[]>}       */      _groupDeinflectionsByTerm(deinflections) { +        /** @type {Map<string, import('translation-internal').DatabaseDeinflection[]>} */          const result = new Map();          for (const deinflection of deinflections) {              const {deinflectedText} = deinflection; @@ -455,7 +457,7 @@ export class Translator {          /** @type {import('translation-internal').DatabaseDeinflection[]} */          const deinflections = [];          const used = new Set(); -        /** @type {Map<string, import('core').SafeAny>} */ +        /** @type {import('translation-internal').TextCache} */          const sourceCache = new Map(); // For reusing text processors' outputs          for ( @@ -498,14 +500,15 @@ export class Translator {      /**       * @param {import('language').TextProcessorWithId<unknown>[]} textProcessors -     * @param {Map<string, unknown>} processorVariant +     * @param {import('translation-internal').TextProcessorVariant} processorVariant       * @param {string} text -     * @param {Map<string, import('core').SafeAny>} textCache +     * @param {import('translation-internal').TextCache} textCache       * @returns {string}       */      _applyTextProcessors(textProcessors, processorVariant, text, textCache) {          for (const {id, textProcessor: {process}} of textProcessors) {              const setting = processorVariant.get(id); +              let level1 = textCache.get(text);              if (!level1) {                  level1 = new Map(); @@ -522,7 +525,7 @@ export class Translator {                  text = process(text, setting);                  level2.set(setting, text);              } else { -                text = level2.get(setting); +                text = level2.get(setting) || '';              }          } @@ -681,6 +684,7 @@ export class Translator {          /** @type {import('dictionary-database').TermExactRequest[]} */          const termList = [];          const targetList = []; +        /** @type {Map<string, {groups: import('translator').DictionaryEntryGroup[]}>} */          const targetMap = new Map();          for (const group of groupedDictionaryEntries) { @@ -1362,10 +1366,10 @@ export class Translator {      /**       * @param {Map<string, unknown[]>} arrayVariants -     * @returns {Map<string, unknown>[]} +     * @returns {import('translation-internal').TextProcessorVariant[]}       */      _getArrayVariants(arrayVariants) { -        /** @type {Map<string, unknown>[]} */ +        /** @type {import('translation-internal').TextProcessorVariant[]} */          const results = [];          const variantKeys = [...arrayVariants.keys()];          const entryVariantLengths = []; @@ -1376,7 +1380,7 @@ export class Translator {          const totalVariants = entryVariantLengths.reduce((acc, length) => acc * length, 1);          for (let variantIndex = 0; variantIndex < totalVariants; ++variantIndex) { -            /** @type {Map<string, unknown>} */ +            /** @type {import('translation-internal').TextProcessorVariant}} */              const variant = new Map();              let remainingIndex = variantIndex; @@ -2076,6 +2080,7 @@ export class Translator {       * @param {boolean} ascending       */      _updateSortFrequencies(dictionaryEntries, dictionary, ascending) { +        /** @type {Map<number, number>} */          const frequencyMap = new Map();          for (const dictionaryEntry of dictionaryEntries) {              const {definitions, frequencies} = dictionaryEntry; diff --git a/ext/js/pages/settings/backup-controller.js b/ext/js/pages/settings/backup-controller.js index 5c168849..f0876d3f 100644 --- a/ext/js/pages/settings/backup-controller.js +++ b/ext/js/pages/settings/backup-controller.js @@ -574,12 +574,16 @@ export class BackupController {       * @returns {Promise<Blob>}       */      async _exportDatabase(databaseName) { -        const db = await new Dexie(databaseName).open(); +        const DexieConstructor = /** @type {import('dexie').DexieConstructor} */ (/** @type {unknown} */ (Dexie)); +        const db = new DexieConstructor(databaseName); +        await db.open(); +        /** @type {unknown} */ +        // @ts-expect-error - The export function is declared as an extension which has no type information.          const blob = await db.export({              progressCallback: this._databaseExportProgressCallback.bind(this)          }); -        await db.close(); -        return blob; +        db.close(); +        return /** @type {Blob} */ (blob);      }      /** */ diff --git a/ext/js/pages/settings/dictionary-import-controller.js b/ext/js/pages/settings/dictionary-import-controller.js index f63eb49e..ecfadc1f 100644 --- a/ext/js/pages/settings/dictionary-import-controller.js +++ b/ext/js/pages/settings/dictionary-import-controller.js @@ -306,6 +306,7 @@ export class DictionaryImportController {       * @param {Error[]} errors       */      _showErrors(errors) { +        /** @type {Map<string, number>} */          const uniqueErrors = new Map();          for (const error of errors) {              log.error(error); diff --git a/ext/js/templates/anki-template-renderer.js b/ext/js/templates/anki-template-renderer.js index ae3e7a36..888be9b0 100644 --- a/ext/js/templates/anki-template-renderer.js +++ b/ext/js/templates/anki-template-renderer.js @@ -659,12 +659,19 @@ export class AnkiTemplateRenderer {      }      /** +     * @param {import('template-renderer').HelperOptions} options +     * @returns {import('anki-templates').NoteData} +     */ +    _getNoteDataFromOptions(options) { +        return options.data.root; +    } + +    /**       * @type {import('template-renderer').HelperFunction<string>}       */      _formatGlossary(args, _context, options) {          const [dictionary, content] = /** @type {[dictionary: string, content: import('dictionary-data').TermGlossaryContent]} */ (args); -        /** @type {import('anki-templates').NoteData} */ -        const data = options.data.root; +        const data = this._getNoteDataFromOptions(options);          if (typeof content === 'string') { return this._safeString(this._stringToMultiLineHtml(content)); }          if (!(typeof content === 'object' && content !== null)) { return ''; }          switch (content.type) { @@ -703,8 +710,7 @@ export class AnkiTemplateRenderer {       * @type {import('template-renderer').HelperFunction<boolean>}       */      _hasMedia(args, _context, options) { -        /** @type {import('anki-templates').NoteData} */ -        const data = options.data.root; +        const data = this._getNoteDataFromOptions(options);          return this._mediaProvider.hasMedia(data, args, options.hash);      } @@ -712,8 +718,7 @@ export class AnkiTemplateRenderer {       * @type {import('template-renderer').HelperFunction<?string>}       */      _getMedia(args, _context, options) { -        /** @type {import('anki-templates').NoteData} */ -        const data = options.data.root; +        const data = this._getNoteDataFromOptions(options);          return this._mediaProvider.getMedia(data, args, options.hash);      } diff --git a/ext/js/templates/template-renderer-media-provider.js b/ext/js/templates/template-renderer-media-provider.js index 2f238e20..c4b07369 100644 --- a/ext/js/templates/template-renderer-media-provider.js +++ b/ext/js/templates/template-renderer-media-provider.js @@ -81,6 +81,8 @@ export class TemplateRendererMediaProvider {          let {value} = data;          const {escape = true} = namedArgs;          if (escape) { +            // Handlebars is a custom version of the library without type information, so it's assumed to be "any". +            // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment              value = Handlebars.Utils.escapeExpression(value);          }          return value; diff --git a/ext/js/templates/template-renderer.js b/ext/js/templates/template-renderer.js index 7bb93aa2..c5b7cd63 100644 --- a/ext/js/templates/template-renderer.js +++ b/ext/js/templates/template-renderer.js @@ -117,6 +117,8 @@ export class TemplateRenderer {          let instance = cache.get(template);          if (typeof instance === 'undefined') {              this._updateCacheSize(this._cacheMaxSize - 1); +            // Handlebars is a custom version of the library without type information, so it's assumed to be "any". +            // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment              instance = /** @type {import('handlebars').TemplateDelegate<import('anki-templates').NoteData>} */ (Handlebars.compileAST(template));              cache.set(template, instance);          } diff --git a/test/dom-text-scanner.test.js b/test/dom-text-scanner.test.js index b366cadd..4ec3a44d 100644 --- a/test/dom-text-scanner.test.js +++ b/test/dom-text-scanner.test.js @@ -85,8 +85,13 @@ function createAbsoluteGetComputedStyle(window) {      return (element, ...args) => {          const style = getComputedStyleOld(element, ...args);          return new Proxy(style, { +            /** +             * @param {CSSStyleDeclaration} target +             * @param {string|symbol} property +             * @returns {unknown} +             */              get: (target, property) => { -                let result = /** @type {import('core').SafeAny} */ (target)[property]; +                let result = /** @type {Record<string|symbol, unknown>} */ (/** @type {unknown} */ (target))[property];                  if (typeof result === 'string') {                      /**                       * @param {string} g0 diff --git a/test/fixtures/dom-test.js b/test/fixtures/dom-test.js index 459383cc..364612f6 100644 --- a/test/fixtures/dom-test.js +++ b/test/fixtures/dom-test.js @@ -28,7 +28,9 @@ function prepareWindow(window) {      // Define innerText setter as an alias for textContent setter      Object.defineProperty(window.HTMLDivElement.prototype, 'innerText', { +        /** @returns {string} */          get() { return this.textContent; }, +        /** @param {string} value */          set(value) { this.textContent = value; }      }); diff --git a/test/handlebars.test.js b/test/handlebars.test.js index d65e8c42..8a566f4c 100644 --- a/test/handlebars.test.js +++ b/test/handlebars.test.js @@ -18,6 +18,22 @@  import {describe, test} from 'vitest';  import {Handlebars} from '../ext/lib/handlebars.js'; +/** + * @param {string} template + * @returns {import('handlebars').TemplateDelegate<unknown>} + */ +function compile(template) { +    return Handlebars.compile(template); +} + +/** + * @param {string} template + * @returns {import('handlebars').TemplateDelegate<unknown>} + */ +function compileAST(template) { +    return Handlebars.compileAST(template); +} +  describe('Handlebars', () => {      test('compile vs compileAST 1', ({expect}) => {          const template = '{{~test1~}}'; @@ -26,8 +42,8 @@ describe('Handlebars', () => {              test1: '<div style="font-size: 4em;">Test</div>'          }; -        const instance1 = Handlebars.compile(template); -        const instance2 = Handlebars.compileAST(template); +        const instance1 = compile(template); +        const instance2 = compileAST(template);          const result1 = instance1(data);          const result2 = instance2(data); @@ -44,8 +60,8 @@ describe('Handlebars', () => {              }          }; -        const instance1 = Handlebars.compile(template); -        const instance2 = Handlebars.compileAST(template); +        const instance1 = compile(template); +        const instance2 = compileAST(template);          const result1 = instance1(data);          const result2 = instance2(data); diff --git a/types/ext/translation-internal.d.ts b/types/ext/translation-internal.d.ts index 00056562..26b043b4 100644 --- a/types/ext/translation-internal.d.ts +++ b/types/ext/translation-internal.d.ts @@ -60,3 +60,7 @@ export type TextProcessorMap = Map<          postprocessorOptionsSpace: TextProcessorOptionsSpace;      }  >; + +export type TextProcessorVariant = Map<string, unknown>; + +export type TextCache = Map<string, Map<string, Map<unknown, string>>>; |