Skip to content

Commit

Permalink
Tighten required typing
Browse files Browse the repository at this point in the history
Do not allow implicit any
  • Loading branch information
Lucki committed Mar 2, 2023
1 parent dc7ea25 commit d810df9
Show file tree
Hide file tree
Showing 22 changed files with 198 additions and 75 deletions.
1 change: 1 addition & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ env:
es2021: true
extends:
- 'eslint:recommended'
- 'plugin:@typescript-eslint/recommended-requiring-type-checking'
parser: "@typescript-eslint/parser"
plugins:
- jsdoc
Expand Down
14 changes: 13 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion src/adapter/baseAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions src/adapter/genericJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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
}

Expand Down
3 changes: 2 additions & 1 deletion src/adapter/localFolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)];
Expand Down Expand Up @@ -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.');

Expand Down
18 changes: 17 additions & 1 deletion src/adapter/reddit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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};
5 changes: 3 additions & 2 deletions src/adapter/unsplash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'}/`,
});
}

Expand Down Expand Up @@ -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
}

Expand Down
30 changes: 20 additions & 10 deletions src/adapter/wallhaven.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand Down Expand Up @@ -104,14 +103,25 @@ class WallhavenAdapter extends BaseAdapter {
if (options.hasOwnProperty(key)) {
if (Array.isArray(options[key]))
optionsString += `${key}=${(options[key] as Array<string>).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) {
Expand All @@ -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')));
Expand Down
4 changes: 3 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
});
}

Expand Down
23 changes: 21 additions & 2 deletions src/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<HistoryEntry>((elem: string) => {
const unknownObject = JSON.parse(elem) as unknown;
if (!this._isHistoryEntry(unknownObject))
throw new Error('Failed loading history data.');

return unknownObject;
});
}

Expand Down Expand Up @@ -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};
35 changes: 26 additions & 9 deletions src/historyMenuElements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -99,17 +102,23 @@ 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);
}

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);
Expand All @@ -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);

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/jsonPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<unknown>(targetObject);
const [object, path] = getTarget(chosenElement, inputStringTail);
return [object, inputString.slice(0, inputString.length - inputStringTail.length).replace('@random', String(chosenNumber)) + path];
}
Expand Down
2 changes: 1 addition & 1 deletion src/manager/hydraPaper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/manager/superPaper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit d810df9

Please sign in to comment.