import type { BaseDownloader } from '../../downloaders/base'; import { maybeAwait } from '../../misc/async'; import type { BaseCollectionsImporter, CreateIconSetImporter, CreateIconSetImporterResult, } from '../../types/importers/collections'; import type { ImportedData } from '../../types/importers/common'; /** * Base collections list importer */ export function createBaseCollectionsListImporter>( instance: Downloader, createIconSetImporter: CreateIconSetImporter ): Downloader & BaseCollectionsImporter { const obj = instance as Downloader & BaseCollectionsImporter; // Importers const importers: Record = Object.create(null); // Import status let importing = false; // Import each icon set const importIconSets = async (prefixes: string[]): Promise => { importing = true; // Reuse old data const data: ImportedData = obj.data || { prefixes, iconSets: Object.create(null), }; const iconSets = data.iconSets; // Parse each prefix for (let i = 0; i < prefixes.length; i++) { const prefix = prefixes[i]; let importer = importers[prefix]; if (!importer) { // New item importer = importers[prefix] = await maybeAwait(createIconSetImporter(prefix)); importer._dataUpdated = async (iconSetData) => { data.iconSets[prefix] = iconSetData; if (!importing) { // Call _dataUpdated() if icon set was updated outside of importIconSets() obj._dataUpdated?.(data); } }; await importer.init(); // Data should have been updated in init() continue; } // Item already exists: check for update await importer.checkForUpdate(); } // Change status importing = false; return { prefixes, iconSets, }; }; // Import from directory obj._loadDataFromDirectory = async (path: string) => { if (!obj._loadCollectionsListFromDirectory) { throw new Error('Importer does not implement _loadCollectionsListFromDirectory()'); } const prefixes = await obj._loadCollectionsListFromDirectory(path); if (prefixes) { return await importIconSets(prefixes); } }; // Custom import obj._loadData = async () => { if (!obj._loadCollectionsList) { throw new Error('Importer does not implement _loadCollectionsList()'); } const prefixes = await obj._loadCollectionsList(); if (prefixes) { return await importIconSets(prefixes); } }; // Check for update const checkCollectionsForUpdate = obj.checkForUpdate.bind(obj); const checkIconSetForUpdate = async (prefix: string): Promise => { const importer = importers[prefix]; if (importer) { return await importer.checkForUpdate(); } console.error(`Cannot check "${prefix}" for update: no such icon set`); return false; }; // Check everything for update obj.checkForUpdate = async (): Promise => { let result = await checkCollectionsForUpdate(); const prefixes = obj.data?.prefixes.slice(0) || []; for (let i = 0; i < prefixes.length; i++) { const importer = importers[prefixes[i]]; if (importer) { result = (await importer.checkForUpdate()) || result; } } return result; }; // Set instance properties const baseData: BaseCollectionsImporter = { type: 'collections', checkCollectionsForUpdate, checkIconSetForUpdate, }; Object.assign(obj, baseData); return obj; }