diff --git a/.eslintrc.yml b/.eslintrc.yml index cb1bdc53..2daa659a 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -5,6 +5,7 @@ env: es2021: true extends: - 'eslint:recommended' + - 'plugin:@typescript-eslint/recommended-requiring-type-checking' parser: "@typescript-eslint/parser" plugins: - jsdoc diff --git a/build.sh b/build.sh index f55b24dd..20e7bca0 100755 --- a/build.sh +++ b/build.sh @@ -89,8 +89,20 @@ compile_schemas() { format_js() { check_command "npm" + # Circumvent not found typescript rules that might be mentioned in code comments but will give an error + # when only checking with javascript rules + # https://stackoverflow.com/questions/64614131/how-can-i-disable-definition-for-rule-custom-rule-was-not-found-errors + shopt -s globstar nullglob + for file in "$DESTDIR"/**/*.js; do + sed -i -E "s#@typescript-eslint/await-thenable##g" "$file" + sed -i -E "s#@typescript-eslint/no-unused-vars##g" "$file" + sed -i -E "s#@typescript-eslint/no-unsafe-argument##g" "$file" + sed -i -E "s#@typescript-eslint/no-unsafe-member-access##g" "$file" + sed -i -E "s#@typescript-eslint/no-unsafe-call##g" "$file" + done + # Format js using the official gjs stylesheet and a few manual quirks - npx --silent eslint --config "$SCRIPTDIR/.eslintrc-gjs.yml" --fix "$DESTDIR/**/*.js" + npx --silent eslint --no-eslintrc --config "$SCRIPTDIR/.eslintrc-gjs.yml" --fix "$DESTDIR/**/*.js" } check_ts() { diff --git a/src/adapter/baseAdapter.ts b/src/adapter/baseAdapter.ts index 3827d06a..4c761c99 100755 --- a/src/adapter/baseAdapter.ts +++ b/src/adapter/baseAdapter.ts @@ -52,7 +52,7 @@ abstract class BaseAdapter { const fstream = file.replace(null, false, Gio.FileCreateFlags.NONE, null); // craft new message from details - let request = this._bowl.newGetMessage(historyEntry.source.imageDownloadUrl); + const request = this._bowl.newGetMessage(historyEntry.source.imageDownloadUrl); // start the download const response_data_bytes = await this._bowl.send_and_receive(request); diff --git a/src/adapter/genericJson.ts b/src/adapter/genericJson.ts index d6cbc628..5765a8df 100644 --- a/src/adapter/genericJson.ts +++ b/src/adapter/genericJson.ts @@ -32,7 +32,7 @@ class GenericJsonAdapter extends BaseAdapter { if (!response_body_bytes) throw new Error('Error fetching response.'); - const response_body = JSON.parse(ByteArray.toString(response_body_bytes)); + const response_body: unknown = JSON.parse(ByteArray.toString(response_body_bytes)); const imageJSONPath = this._settings.getString('image-path'); const postJSONPath = this._settings.getString('post-path'); const domainUrl = this._settings.getString('domain'); @@ -115,7 +115,8 @@ class GenericJsonAdapter extends BaseAdapter { }); } } catch (error) { - this._logger.warn(`Failed getting image: ${error}`); + this._logger.warn('Failed getting image'); + this._logger.warn(error); // Do not escalate yet, try again } diff --git a/src/adapter/localFolder.ts b/src/adapter/localFolder.ts index 88d8bf5e..401c5840 100644 --- a/src/adapter/localFolder.ts +++ b/src/adapter/localFolder.ts @@ -31,7 +31,7 @@ class LocalFolderAdapter extends BaseAdapter { reject(new Error('No files found')); return; } - this._logger.debug(`Found ${files.length} possible wallpaper in "${folder.get_path()}"`); + this._logger.debug(`Found ${files.length} possible wallpaper in "${this._settings.getString('folder')}"`); for (let i = 0; i < 20 && wallpaperResult.length < count; i++) { const randomFile = files[Utils.getRandomNumber(files.length)]; @@ -64,6 +64,7 @@ class LocalFolderAdapter extends BaseAdapter { // https://gjs.guide/guides/gio/file-operations.html#copying-and-moving-files // This function was rewritten by Gio._promisify // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/await-thenable if (!await sourceFile.copy_async(targetFile, Gio.FileCopyFlags.NONE, GLib.PRIORITY_DEFAULT, null, null)) throw new Error('Failed copying image.'); diff --git a/src/adapter/reddit.ts b/src/adapter/reddit.ts index ba724ed9..24133b64 100644 --- a/src/adapter/reddit.ts +++ b/src/adapter/reddit.ts @@ -55,7 +55,9 @@ class RedditAdapter extends BaseAdapter { const response_body_bytes = await this._bowl.send_and_receive(message); - const response_body: RedditResponse = JSON.parse(ByteArray.toString(response_body_bytes)); + const response_body = JSON.parse(ByteArray.toString(response_body_bytes)) as unknown; + if (!this._isRedditResponse(response_body)) + throw new Error('Unexpected response'); const filteredSubmissions = response_body.data.children.filter(child => { if (child.data.post_hint !== 'image') @@ -101,6 +103,20 @@ class RedditAdapter extends BaseAdapter { return wallpaperResult; } + + private _isRedditResponse(object: unknown): object is RedditResponse { + if (typeof object === 'object' && + object && + 'data' in object && + typeof object.data === 'object' && + object.data && + 'children' in object.data && + Array.isArray(object.data.children) + ) + return true; + + return false; + } } export {RedditAdapter}; diff --git a/src/adapter/unsplash.ts b/src/adapter/unsplash.ts index 90f3717d..78e188b4 100644 --- a/src/adapter/unsplash.ts +++ b/src/adapter/unsplash.ts @@ -23,7 +23,7 @@ class UnsplashAdapter extends BaseAdapter { id: id ?? '-1', name, schemaID: SettingsModule.RWG_SETTINGS_SCHEMA_SOURCES_UNSPLASH, - schemaPath: `${SettingsModule.RWG_SETTINGS_SCHEMA_PATH}/sources/unsplash/${id}/`, + schemaPath: `${SettingsModule.RWG_SETTINGS_SCHEMA_PATH}/sources/unsplash/${id ?? '-1'}/`, }); } @@ -76,7 +76,8 @@ class UnsplashAdapter extends BaseAdapter { if (historyEntry && !this._includesWallpaper(wallpaperResult, historyEntry.source.imageDownloadUrl)) wallpaperResult.push(historyEntry); } catch (error) { - this._logger.warn(`Failed getting image: ${error}`); + this._logger.warn('Failed getting image.'); + this._logger.warn(error); // Do not escalate yet, try again } diff --git a/src/adapter/wallhaven.ts b/src/adapter/wallhaven.ts index bad8f207..d16b4d70 100644 --- a/src/adapter/wallhaven.ts +++ b/src/adapter/wallhaven.ts @@ -61,12 +61,11 @@ class WallhavenAdapter extends BaseAdapter { this._logger.debug(`Search URL: ${url}`); const response_body_bytes = await this._bowl.send_and_receive(message); - let response: WallhavenSearchResponse['data']; - try { - response = JSON.parse(ByteArray.toString(response_body_bytes)).data; - } catch { - throw new Error('Error parsing API.'); - } + const wallhavenResponse = JSON.parse(ByteArray.toString(response_body_bytes)) as unknown; + if (!this._isWallhavenResponse(wallhavenResponse)) + throw new Error('Unexpected response'); + + const response = wallhavenResponse.data; if (!response || response.length === 0) throw new Error('Empty response'); @@ -104,14 +103,25 @@ class WallhavenAdapter extends BaseAdapter { if (options.hasOwnProperty(key)) { if (Array.isArray(options[key])) optionsString += `${key}=${(options[key] as Array).join()}&`; - else if (options[key] !== '') - optionsString += `${key}=${options[key]}&`; + else if (typeof options[key] === 'string' && options[key] !== '') + optionsString += `${key}=${options[key] as string}&`; } } return optionsString; } + private _isWallhavenResponse(object: unknown): object is WallhavenSearchResponse { + if (typeof object === 'object' && + object && + 'data' in object && + Array.isArray(object.data) + ) + return true; + + return false; + } + private _readOptionsFromSettings() { const keywords = this._settings.getString('keyword').split(','); if (keywords.length > 0) { @@ -126,13 +136,13 @@ class WallhavenAdapter extends BaseAdapter { return elem.trim(); }); - let categories = []; + const categories = []; categories.push(Number(this._settings.getBoolean('category-general'))); // + is implicit conversion to int categories.push(Number(this._settings.getBoolean('category-anime'))); categories.push(Number(this._settings.getBoolean('category-people'))); this._options.categories = categories.join(''); - let purity = []; + const purity = []; purity.push(Number(this._settings.getBoolean('allow-sfw'))); purity.push(Number(this._settings.getBoolean('allow-sketchy'))); purity.push(Number(this._settings.getBoolean('allow-nsfw'))); diff --git a/src/extension.ts b/src/extension.ts index f9f91a78..bb523c7a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -38,8 +38,10 @@ class Extension { }).catch(error => { if (this._logger) this._logger.error(error); - else + else if (error instanceof Error) logError(error); + else + logError(new Error('Unknown error')); }); } diff --git a/src/history.ts b/src/history.ts index a2fbae21..aa1b3bb9 100644 --- a/src/history.ts +++ b/src/history.ts @@ -137,8 +137,12 @@ class HistoryController { this.size = this._settings.getInt('history-length'); const stringHistory: string[] = this._settings.getStrv('history'); - this.history = stringHistory.map((elem: string) => { - return JSON.parse(elem); + this.history = stringHistory.map((elem: string) => { + const unknownObject = JSON.parse(elem) as unknown; + if (!this._isHistoryEntry(unknownObject)) + throw new Error('Failed loading history data.'); + + return unknownObject; }); } @@ -198,6 +202,21 @@ class HistoryController { } } } + + private _isHistoryEntry(object: unknown): object is HistoryEntry { + if (typeof object === 'object' && + object && + 'timestamp' in object && + typeof object.timestamp === 'number' && + 'id' in object && + typeof object.id === 'string' && + 'path' in object && + typeof object.path === 'string' + ) + return true; + + return false; + } } export {HistoryEntry, HistoryController}; diff --git a/src/historyMenuElements.ts b/src/historyMenuElements.ts index 53eeb442..a995f09b 100644 --- a/src/historyMenuElements.ts +++ b/src/historyMenuElements.ts @@ -88,8 +88,11 @@ const HistoryElement = GObject.registerClass({ this.historyEntry.source.authorUrl !== null) { const authorItem = new PopupMenu.PopupMenuItem(`Image By: ${this.historyEntry.source.author}`); authorItem.connect('activate', () => { - if (this.historyEntry.source.authorUrl) - Utils.execCheck(['xdg-open', this.historyEntry.source.authorUrl]).catch(this._logger.error); + if (this.historyEntry.source.authorUrl) { + Utils.execCheck(['xdg-open', this.historyEntry.source.authorUrl]).catch(error => { + this._logger.error(error); + }); + } }); this.menu.addMenuItem(authorItem); @@ -99,8 +102,11 @@ const HistoryElement = GObject.registerClass({ this.historyEntry.source.sourceUrl !== null) { const sourceItem = new PopupMenu.PopupMenuItem(`Image From: ${this.historyEntry.source.source}`); sourceItem.connect('activate', () => { - if (this.historyEntry.source.sourceUrl) - Utils.execCheck(['xdg-open', this.historyEntry.source.sourceUrl]).catch(this._logger.error); + if (this.historyEntry.source.sourceUrl) { + Utils.execCheck(['xdg-open', this.historyEntry.source.sourceUrl]).catch(error => { + this._logger.error(error); + }); + } }); this.menu.addMenuItem(sourceItem); @@ -108,8 +114,11 @@ const HistoryElement = GObject.registerClass({ const imageUrlItem = new PopupMenu.PopupMenuItem('Open Image In Browser'); imageUrlItem.connect('activate', () => { - if (this.historyEntry.source.imageLinkUrl) - Utils.execCheck(['xdg-open', this.historyEntry.source.imageLinkUrl]).catch(this._logger.error); + if (this.historyEntry.source.imageLinkUrl) { + Utils.execCheck(['xdg-open', this.historyEntry.source.imageLinkUrl]).catch(error => { + this._logger.error(error); + }); + } }); this.menu.addMenuItem(imageUrlItem); @@ -132,7 +141,9 @@ const HistoryElement = GObject.registerClass({ const copyToFavorites = new PopupMenu.PopupMenuItem('Save For Later'); copyToFavorites.connect('activate', () => { - this._saveImage().catch(this._logger.error); + this._saveImage().catch(error => { + this._logger.error(error); + }); }); this.menu.addMenuItem(copyToFavorites); @@ -222,14 +233,18 @@ const HistoryElement = GObject.registerClass({ // This function was rewritten by Gio._promisify // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/await-thenable if (!await sourceFile.copy_async(targetFile, Gio.FileCopyFlags.NONE, GLib.PRIORITY_DEFAULT, null, null)) throw new Error('Failed copying image.'); // https://gjs.guide/guides/gio/file-operations.html#writing-file-contents // This function was rewritten by Gio._promisify // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/await-thenable const [success, message]: [boolean, string] = await targetInfoFile.replace_contents_bytes_async( - // @ts-expect-error Don't know from where to import + // FIXME: Don't know from where to import + // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call new TextEncoder().encode(JSON.stringify(this.historyEntry.source, null, '\t')), null, false, @@ -324,7 +339,9 @@ class StatusElement { } startLoading() { - // @ts-expect-error Don't know where this is defined + // FIXME: Don't know where this is defined + // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-call this.icon.ease({ opacity: 20, duration: 1337, diff --git a/src/jsonPath.ts b/src/jsonPath.ts index 648a122d..4d7f0bb4 100644 --- a/src/jsonPath.ts +++ b/src/jsonPath.ts @@ -44,7 +44,7 @@ function getTarget(inputObject: unknown, inputString: string): [object: unknown, switch (indexString) { case '@random': { - const [chosenElement, chosenNumber] = _randomElement(targetObject); + const [chosenElement, chosenNumber] = _randomElement(targetObject); const [object, path] = getTarget(chosenElement, inputStringTail); return [object, inputString.slice(0, inputString.length - inputStringTail.length).replace('@random', String(chosenNumber)) + path]; } diff --git a/src/manager/hydraPaper.ts b/src/manager/hydraPaper.ts index 55fcb3d6..447fc2d9 100644 --- a/src/manager/hydraPaper.ts +++ b/src/manager/hydraPaper.ts @@ -70,7 +70,7 @@ class HydraPaper implements WallpaperManager { this._cancellable = new Gio.Cancellable(); // hydrapaper [--darkmode] --cli PATH PATH PATH - this._logger.debug(`Running command: ${command}`); + this._logger.debug(`Running command: ${command.toString()}`); await Utils.execCheck(command, this._cancellable); this._cancellable = null; diff --git a/src/manager/superPaper.ts b/src/manager/superPaper.ts index 529c0953..2dd79493 100644 --- a/src/manager/superPaper.ts +++ b/src/manager/superPaper.ts @@ -80,7 +80,7 @@ class Superpaper implements WallpaperManager { this._cancellable = new Gio.Cancellable(); - this._logger.debug(`Running command: "${command}"`); + this._logger.debug(`Running command: ${command.toString()}`); await Utils.execCheck(command, this._cancellable); this._cancellable = null; diff --git a/src/prefs.ts b/src/prefs.ts index fc273cbf..b0071106 100644 --- a/src/prefs.ts +++ b/src/prefs.ts @@ -129,11 +129,11 @@ class RandomWallpaperSettings { this._sources.forEach(id => { const sourceRow = new SourceRow(undefined, id); - (this._builder.get_object('sources_list') as Adw.PreferencesGroup).add(sourceRow); + this._builder.get_object('sources_list').add(sourceRow); sourceRow.button_delete.connect('clicked', () => { sourceRow.clearConfig(); - (this._builder.get_object('sources_list') as Adw.PreferencesGroup).remove(sourceRow); + this._builder.get_object('sources_list').remove(sourceRow); Utils.removeItemOnce(this._sources, id); this._saveSources(); }); @@ -141,11 +141,15 @@ class RandomWallpaperSettings { import('./manager/wallpaperManager.js').then(module => { if (module.getWallpaperManager()?.isAvailable()) - (this._builder.get_object('multiple_displays_row') as Adw.ActionRow).set_sensitive(true); - }).catch(this._logger.error); + this._builder.get_object('multiple_displays_row').set_sensitive(true); + }).catch(error => { + this._logger.error(error); + }); }).catch(error => { - logError(error); - throw error; + if (error instanceof Error) + logError(error); + else + logError(new Error('Unknown error')); }); } @@ -192,7 +196,7 @@ class RandomWallpaperSettings { this._backendConnection.setBoolean('request-new-wallpaper', true); }); - const sourceRowList = this._builder.get_object('sources_list') as Adw.PreferencesGroup; + const sourceRowList = this._builder.get_object('sources_list'); this._builder.get_object('button_new_source').connect('clicked', () => { const sourceRow = new SourceRow(); sourceRowList.add(sourceRow); @@ -209,7 +213,7 @@ class RandomWallpaperSettings { } private _bindHistorySection(window: Adw.PreferencesWindow) { - const entryRow = this._builder.get_object('row_favorites_folder') as Adw.EntryRow; + const entryRow = this._builder.get_object('row_favorites_folder'); entryRow.text = this._settings.getString('favorites-folder'); this._settings.bind('history-length', @@ -263,10 +267,10 @@ class RandomWallpaperSettings { this._sources = this._settings.getStrv('sources'); // this._sources.sort((a, b) => { - // let path1 = `${Settings.RWG_SETTINGS_SCHEMA_PATH}/sources/general/${a}/`; - // let settingsGeneral1 = new Settings.Settings(Settings.RWG_SETTINGS_SCHEMA_SOURCES_GENERAL, path1); - // let path2 = `${Settings.RWG_SETTINGS_SCHEMA_PATH}/sources/general/${b}/`; - // let settingsGeneral2 = new Settings.Settings(Settings.RWG_SETTINGS_SCHEMA_SOURCES_GENERAL, path2); + // const path1 = `${Settings.RWG_SETTINGS_SCHEMA_PATH}/sources/general/${a}/`; + // const settingsGeneral1 = new Settings.Settings(Settings.RWG_SETTINGS_SCHEMA_SOURCES_GENERAL, path1); + // const path2 = `${Settings.RWG_SETTINGS_SCHEMA_PATH}/sources/general/${b}/`; + // const settingsGeneral2 = new Settings.Settings(Settings.RWG_SETTINGS_SCHEMA_SOURCES_GENERAL, path2); // const nameA = settingsGeneral1.get('name', 'string').toUpperCase(); // const nameB = settingsGeneral2.get('name', 'string').toUpperCase(); @@ -275,10 +279,10 @@ class RandomWallpaperSettings { // }); this._sources.sort((a, b) => { - let path1 = `${Settings.RWG_SETTINGS_SCHEMA_PATH}/sources/general/${a}/`; - let settingsGeneral1 = new Settings.Settings(Settings.RWG_SETTINGS_SCHEMA_SOURCES_GENERAL, path1); - let path2 = `${Settings.RWG_SETTINGS_SCHEMA_PATH}/sources/general/${b}/`; - let settingsGeneral2 = new Settings.Settings(Settings.RWG_SETTINGS_SCHEMA_SOURCES_GENERAL, path2); + const path1 = `${Settings.RWG_SETTINGS_SCHEMA_PATH}/sources/general/${a}/`; + const settingsGeneral1 = new Settings.Settings(Settings.RWG_SETTINGS_SCHEMA_SOURCES_GENERAL, path1); + const path2 = `${Settings.RWG_SETTINGS_SCHEMA_PATH}/sources/general/${b}/`; + const settingsGeneral2 = new Settings.Settings(Settings.RWG_SETTINGS_SCHEMA_SOURCES_GENERAL, path2); return settingsGeneral1.getEnum('type') - settingsGeneral2.getEnum('type'); }); } diff --git a/src/randomWallpaperMenu.ts b/src/randomWallpaperMenu.ts index 47efa54f..7235e4ab 100644 --- a/src/randomWallpaperMenu.ts +++ b/src/randomWallpaperMenu.ts @@ -113,11 +113,12 @@ class RandomWallpaperMenu { // Open Wallpaper Folder openFolder.connect('activate', () => { const uri = GLib.filename_to_uri(this._wallpaperController.wallpaperLocation, ''); - Utils.execCheck(['xdg-open', uri]).catch(this._logger.error); + Utils.execCheck(['xdg-open', uri]).catch(error => { + this._logger.error(error); + }); }); openSettings.connect('activate', () => { - // FIXME: Unhandled promise rejection. To suppress this warning, add an error handler to your promise chain with .catch() or a try-catch block around your await expression. Gio.DBus.session.call( 'org.gnome.Shell.Extensions', '/org/gnome/Shell/Extensions', @@ -127,7 +128,9 @@ class RandomWallpaperMenu { null, Gio.DBusCallFlags.NONE, -1, - null); + null).catch(error => { + this._logger.error(error); + }); }); this._panelMenu.menu.connect('open-state-changed', (_, open) => { diff --git a/src/settings.ts b/src/settings.ts index 9288143c..23dc3511 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -88,7 +88,7 @@ class Settings { if (this._settings.set_boolean(key, value)) this._save(); else - throw new Error(`Could not set ${key} (type: boolean) with the value ${value}`); + throw new Error(`Could not set ${key} (type: boolean) with the value ${String(value)}`); } setEnum(key: string, value: number) { @@ -116,7 +116,7 @@ class Settings { if (this._settings.set_strv(key, value)) this._save(); else - throw new Error(`Could not set ${key} (type: string[]) with the value ${value}`); + throw new Error(`Could not set ${key} (type: string[]) with the value "${value.toString()}"`); } private _save() { diff --git a/src/soupBowl.ts b/src/soupBowl.ts index 8e4425dc..2994baee 100644 --- a/src/soupBowl.ts +++ b/src/soupBowl.ts @@ -4,6 +4,7 @@ * libSoup is accessed through the SoupBowl wrapper to support libSoup3 and libSoup2.4 simultaneously in the extension * runtime and in the preferences window. */ +import * as GLib from 'gi://GLib'; import * as Soup from 'gi://Soup'; import {Logger} from './logger.js'; @@ -27,9 +28,10 @@ class SoupBowl { return Soup.Message.new('GET', uri); } + // Possibly wrong version here causing ignores to type checks private _send_and_receive_soup24(soupMessage: Soup.Message): Promise { return new Promise((resolve, reject) => { - // @ts-ignore Possibly wrong version here + // @ts-ignore this._session.queue_message(soupMessage, (session, msg) => { if (!msg.response_body) { reject(new Error('Message has no response body')); @@ -42,19 +44,26 @@ class SoupBowl { }); } + // Possibly wrong version here causing ignores to type checks private _send_and_receive_soup30(soupMessage: Soup.Message): Promise { return new Promise((resolve, reject) => { - // @ts-ignore Possibly wrong version here + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unsafe-call this._session.send_and_read_async(soupMessage, 0, null, (session: Soup.Session, message: Soup.Message) => { - // @ts-ignore Possibly wrong version here - const res_data = session.send_and_read_finish(message); + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const res_data = session.send_and_read_finish(message) as GLib.Bytes | null; if (!res_data) { reject(new Error('Message has no response body')); return; } const response_body_bytes = res_data.get_data(); - resolve(response_body_bytes); + + if (response_body_bytes) + resolve(response_body_bytes); + else + reject(new Error('Empty response')); }); }); } diff --git a/src/timer.ts b/src/timer.ts index 2ced7100..8ac3723b 100644 --- a/src/timer.ts +++ b/src/timer.ts @@ -44,7 +44,10 @@ class AFTimer { this._logger.debug('Continuing timer'); this._paused = false; - this.start(); + + // We don't care about awaiting. This should start immediately and + // run continuously in the background. + void this.start(); } isActive() { @@ -130,8 +133,12 @@ class AFTimer { if (this._timeoutEndCallback) { this._timeoutEndCallback().then(() => { this._reset(); - this.start().catch(this._logger.error); - }).catch(this._logger.error).finally(() => { + this.start().catch(error => { + this._logger.error(error); + }); + }).catch(error => { + this._logger.error(error); + }).finally(() => { return GLib.SOURCE_REMOVE; }); } diff --git a/src/ui/sourceRow.ts b/src/ui/sourceRow.ts index 6460c691..6db4924a 100644 --- a/src/ui/sourceRow.ts +++ b/src/ui/sourceRow.ts @@ -120,7 +120,7 @@ const SourceRow = GObject.registerClass({ } private _fillRow(type: number) { - let targetWidget = this._getSettingsGroup(type); + const targetWidget = this._getSettingsGroup(type); if (targetWidget !== null) this._settings_container.set_child(targetWidget); } diff --git a/src/utils.ts b/src/utils.ts index f7bd2e6c..f6df5a3a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -132,6 +132,7 @@ function getMonitorCount(): number { // FIXME: wrong version in definition // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-call return defaultDisplay.get_n_monitors() as number; } diff --git a/src/wallpaperController.ts b/src/wallpaperController.ts index 24cc77ae..5f164839 100644 --- a/src/wallpaperController.ts +++ b/src/wallpaperController.ts @@ -53,11 +53,17 @@ class WallpaperController { constructor() { let xdg_cache_home = GLib.getenv('XDG_CACHE_HOME'); - if (!xdg_cache_home) - xdg_cache_home = `${GLib.getenv('HOME')}/.cache`; + if (!xdg_cache_home) { + const home = GLib.getenv('HOME'); + + if (home) + xdg_cache_home = `${home}/.cache`; + else + xdg_cache_home = '/tmp'; + } this.wallpaperLocation = `${xdg_cache_home}/${Self.metadata['uuid']}/wallpapers/`; - let mode = 0o0755; + const mode = 0o0755; GLib.mkdir_with_parents(this.wallpaperLocation, mode); this._historyController = new HistoryModule.HistoryController(this.wallpaperLocation); @@ -72,7 +78,9 @@ class WallpaperController { this._backendConnection.observe('clear-history', () => this._clearHistory()); this._backendConnection.observe('open-folder', () => this._openFolder()); this._backendConnection.observe('pause-timer', () => this._pauseTimer()); - this._backendConnection.observe('request-new-wallpaper', () => this._requestNewWallpaper().catch(this._logger.error)); + this._backendConnection.observe('request-new-wallpaper', () => this._requestNewWallpaper().catch(error => { + this._logger.error(error); + })); this._settings.observe('history-length', () => this._updateHistory()); this._settings.observe('auto-fetch', () => this._updateAutoFetching()); @@ -83,8 +91,11 @@ class WallpaperController { this._updateAutoFetching(); // load a new wallpaper on startup - if (this._settings.getBoolean('fetch-on-startup')) - this.fetchNewWallpaper().catch(this._logger.error); + if (this._settings.getBoolean('fetch-on-startup')) { + this.fetchNewWallpaper().catch(error => { + this._logger.error(error); + }); + } // Initialize favorites folder // TODO: There's probably a better place for this @@ -125,7 +136,7 @@ class WallpaperController { private _openFolder() { if (this._backendConnection.getBoolean('open-folder')) { - let uri = GLib.filename_to_uri(this.wallpaperLocation, ''); + const uri = GLib.filename_to_uri(this.wallpaperLocation, ''); Gio.AppInfo.launch_default_for_uri(uri, Gio.AppLaunchContext.new()); this._backendConnection.setBoolean('open-folder', false); } @@ -180,7 +191,9 @@ class WallpaperController { return this.fetchNewWallpaper(); }); this._timer.setMinutes(this._autoFetch.duration); - this._timer.start().catch(this._logger.error); + this._timer.start().catch(error => { + this._logger.error(error); + }); } else { this._timer.stop(); } @@ -383,7 +396,9 @@ class WallpaperController { const generalPostCommandArray = this._getCommandArray(commandString, currentWallpaperPath); if (generalPostCommandArray !== null) { // Do not await this call, let it be one shot - Utils.execCheck(generalPostCommandArray).catch(this._logger.error); + Utils.execCheck(generalPostCommandArray).catch(error => { + this._logger.error(error); + }); } } @@ -511,7 +526,7 @@ class WallpaperController { return null; // Replace variables - const variables = new Map(); + const variables = new Map(); variables.set('%wallpaper_path%', historyElementPath); variables.forEach((value, key) => { @@ -560,10 +575,14 @@ class WallpaperController { // Only change the background - the lock screen wouldn't be visible anyway // because this function is only used for hover preview if (this._resetWallpaper) { - this._setBackground(paths, 0).catch(this._logger.error); + this._setBackground(paths, 0).catch(error => { + this._logger.error(error); + }); this._resetWallpaper = false; } else if (this._previewId !== undefined) { - this._setBackground(paths, 0).catch(this._logger.error); + this._setBackground(paths, 0).catch(error => { + this._logger.error(error); + }); } return GLib.SOURCE_REMOVE;