Merge pull request #73 from MillenniumEarl/2.0.0-ts-cf-autofix

Apply fixes from CodeFactor
pull/74/head
Millennium Earl 2021-03-04 10:47:05 +01:00 committed by GitHub
commit a3cb6ab416
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 104 additions and 104 deletions

View File

@ -1,5 +1,5 @@
/*
to use this example, create an .env file
/*
to use this example, create an .env file
in the project root with the following values:
F95_USERNAME = YOUR_USERNAME
@ -12,12 +12,12 @@ F95_PASSWORD = YOUR_PASSWORD
import dotenv from "dotenv";
// Modules from file
import { login,
getUserData,
getLatestUpdates,
LatestSearchQuery,
Game,
searchHandiwork,
import { login,
getUserData,
getLatestUpdates,
LatestSearchQuery,
Game,
searchHandiwork,
HandiworkSearchQuery
} from "./index.js";

View File

@ -59,7 +59,7 @@ export function isLogged(): boolean { return shared.isLogged; };
/**
* Log in to the F95Zone platform.
*
*
* This **must** be the first operation performed before accessing any other script functions.
*/
export async function login(username: string, password: string): Promise<LoginResult> {
@ -102,7 +102,7 @@ export async function login(username: string, password: string): Promise<LoginRe
/**
* Chek if exists a new version of the handiwork.
*
*
* You **must** be logged in to the portal before calling this method.
*/
export async function checkIfHandiworkHasUpdate(hw: HandiWork): Promise<boolean> {
@ -127,9 +127,9 @@ export async function checkIfHandiworkHasUpdate(hw: HandiWork): Promise<boolean>
/**
* Search for one or more handiworks identified by a specific query.
*
*
* You **must** be logged in to the portal before calling this method.
*
*
* @param {HandiworkSearchQuery} query Parameters used for the search.
* @param {Number} limit Maximum number of results. Default: 10
*/
@ -137,12 +137,12 @@ export async function searchHandiwork<T extends IBasic>(query: HandiworkSearchQu
// Check if the user is logged
if (!shared.isLogged) throw new UserNotLogged(USER_NOT_LOGGED);
return await search<T>(query, limit);
return search<T>(query, limit);
};
/**
* Given the url, it gets all the information about the handiwork requested.
*
*
* You **must** be logged in to the portal before calling this method.
*/
export async function getHandiworkFromURL<T extends IBasic>(url: string): Promise<T> {
@ -155,14 +155,14 @@ export async function getHandiworkFromURL<T extends IBasic>(url: string): Promis
if (!isF95URL(url)) throw new Error(`${url} is not a valid F95Zone URL`);
// Get game data
return await getHandiworkInformation<T>(url);
return getHandiworkInformation<T>(url);
};
/**
* Gets the data of the currently logged in user.
*
*
* You **must** be logged in to the portal before calling this method.
*
*
* @returns {Promise<UserProfile>} Data of the user currently logged in
*/
export async function getUserData(): Promise<UserProfile> {
@ -178,9 +178,9 @@ export async function getUserData(): Promise<UserProfile> {
/**
* Gets the latest updated games that match the specified parameters.
*
*
* You **must** be logged in to the portal before calling this method.
*
*
* @param {LatestSearchQuery} query Parameters used for the search.
* @param {Number} limit Maximum number of results. Default: 10
*/
@ -196,7 +196,7 @@ export async function getLatestUpdates<T extends IBasic>(query: LatestSearchQuer
// Get the data from urls
const promiseList = urls.map((u: string) => getHandiworkInformation<T>(u));
return await Promise.all(promiseList);
return Promise.all(promiseList);
};
//#endregion

View File

@ -45,7 +45,7 @@ export default class Thread {
public get id() { return this._id; }
/**
* URL of the thread.
*
*
* It may vary depending on any versions of the contained product.
*/
public get url() { return this._url; }
@ -85,8 +85,8 @@ export default class Thread {
//#endregion Getters
/**
* Initializes an object for mapping a thread.
*
* Initializes an object for mapping a thread.
*
* The unique ID of the thread must be specified.
*/
constructor(id: number) { this._id = id; }
@ -167,7 +167,7 @@ export default class Thread {
}
/**
* It processes the rating of the thread
* It processes the rating of the thread
* starting from the data contained in the JSON+LD tag.
*/
private parseRating(data: TJsonLD): TRating {
@ -241,7 +241,7 @@ export default class Thread {
/**
* Gets the post in the `index` position with respect to the posts in the thread.
*
*
* `index` must be greater or equal to 1.
* If the post is not found, `null` is returned.
*/

View File

@ -149,7 +149,7 @@ export default class UserProfile extends PlatformUser {
}
// Wait for the promises to resolve
return await Promise.all(responsePromiseList);
return Promise.all(responsePromiseList);
}
/**

View File

@ -11,7 +11,7 @@ export default class PrefixParser {
//#region Private methods
/**
* Gets the key associated with a given value from a dictionary.
* @param {Object} object Dictionary to search
* @param {Object} object Dictionary to search
* @param {Any} value Value associated with the key
* @returns {String|undefined} Key found or undefined
*/
@ -43,7 +43,7 @@ export default class PrefixParser {
}
/**
* Search within the platform prefixes for the
* Search within the platform prefixes for the
* desired element and return the dictionary that contains it.
* @param element Element to search in the prefixes as a key or as a value
*/

View File

@ -13,21 +13,21 @@ import ThreadSearchQuery, { TThreadOrder } from './thread-search-query.js';
// Type definitions
/**
* Method of sorting results. Try to unify the two types of
* sorts in the "Latest" section and in the "Thread search"
* section. Being dynamic research, if a sorting type is not
* Method of sorting results. Try to unify the two types of
* sorts in the "Latest" section and in the "Thread search"
* section. Being dynamic research, if a sorting type is not
* available, the replacement sort is chosen.
*
*
* `date`: Order based on the latest update
*
* `likes`: Order based on the number of likes received. Replacement: `replies`.
*
*
* `relevance`: Order based on the relevance of the result (or rating).
*
*
* `replies`: Order based on the number of answers to the thread. Replacement: `views`.
*
*
* `title`: Order based on the growing alphabetical order of the titles.
*
*
* `views`: Order based on the number of visits. Replacement: `replies`.
*/
type THandiworkOrder = "date" | "likes" | "relevance" | "replies" | "title" | "views";
@ -80,8 +80,8 @@ export default class HandiworkSearchQuery implements IQuery {
//#region Public methods
/**
* Select what kind of search should be
* performed based on the properties of
* Select what kind of search should be
* performed based on the properties of
* the query.
*/
public selectSearchType(): "latest" | "thread" {
@ -89,8 +89,8 @@ export default class HandiworkSearchQuery implements IQuery {
const MAX_TAGS_LATEST_SEARCH = 5;
const DEFAULT_SEARCH_TYPE = "latest";
// If the keywords are set or the number
// of included tags is greather than 5,
// If the keywords are set or the number
// of included tags is greather than 5,
// we must perform a thread search
if (this.keywords || this.includedTags.length > MAX_TAGS_LATEST_SEARCH) return "thread";
@ -156,7 +156,7 @@ export default class HandiworkSearchQuery implements IQuery {
private castToThread(): ThreadSearchQuery {
// Cast the basic query object and copy common values
const query: ThreadSearchQuery = new ThreadSearchQuery;
Object.keys(this).forEach(key => {
Object.keys(this).forEach(key => {
if (query.hasOwnProperty(key)) {
query[key] = this[key];
}

View File

@ -29,15 +29,15 @@ export default class LatestSearchQuery implements IQuery {
public category: TCategory = 'games';
/**
* Ordering type.
*
* Ordering type.
*
* Default: `date`.
*/
public order: TLatestOrder = 'date';
/**
* Date limit in days, to be understood as "less than".
* Use `1` to indicate "today" or `null` to indicate "anytime".
*
*
* Default: `null`
*/
public date: TDate = null;
@ -74,7 +74,7 @@ export default class LatestSearchQuery implements IQuery {
const decoded = decodeURIComponent(url.toString());
// Fetch the result
return await fetchGETResponse(decoded);
return fetchGETResponse(decoded);
}
public findNearestDate(d: Date): TDate {
@ -124,7 +124,7 @@ export default class LatestSearchQuery implements IQuery {
}
/**
*
*
*/
private dateDiffInDays(a: Date, b: Date) {
const MS_PER_DAY = 1000 * 60 * 60 * 24;

View File

@ -82,7 +82,7 @@ export default class ThreadSearchQuery implements IQuery {
const params = this.preparePOSTParameters();
// Return the POST response
return await fetchPOSTResponse(urls.F95_SEARCH_URL, params);
return fetchPOSTResponse(urls.F95_SEARCH_URL, params);
}
//#endregion Public methods

View File

@ -25,7 +25,7 @@ export const selectors = {
export const GENERIC = {
/**
* The ID of the user currently logged into
* The ID of the user currently logged into
* the platform in the attribute `data-user-id`.
*/
CURRENT_USER_ID: "span.avatar[data-user-id]",
@ -41,17 +41,17 @@ export const WATCHED_THREAD = {
*/
BODIES: "div.structItem-cell--main",
/**
* Link element containing the partial URL
* Link element containing the partial URL
* of the thread in the `href` attribute.
*
*
* It may be followed by the `/unread` segment.
*
*
* For use within a `WATCHED_THREAD.BODIES` selector.
*/
URL: "div > a[data-tp-primary]",
/**
* Name of the forum to which the thread belongs as text.
*
*
* For use within a `WATCHED_THREAD.BODIES` selector.
*/
FORUM: "div.structItem-cell--main > div.structItem-minor > ul.structItem-parts > li:last-of-type > a",
@ -64,19 +64,19 @@ export const WATCHED_THREAD = {
export const THREAD = {
/**
* Number of pages in the thread (as text of the element).
*
*
* Two identical elements are identified.
*/
LAST_PAGE: "ul.pageNav-main > li:last-child > a",
/**
* Identify the creator of the thread.
*
*
* The ID is contained in the `data-user-id` attribute.
*/
OWNER_ID: "div.uix_headerInner > * a.username[data-user-id]",
/**
* Contains the creation date of the thread.
*
*
* The date is contained in the `datetime` attribute as an ISO string.
*/
CREATION: "div.uix_headerInner > * time",
@ -94,7 +94,7 @@ export const THREAD = {
TITLE: "h1.p-title-value",
/**
* JSON containing thread information.
*
*
* Two different elements are found.
*/
JSONLD: "script[type=\"application/ld+json\"]",
@ -106,44 +106,44 @@ export const THREAD = {
export const POST = {
/**
* Unique post number for the current thread.
*
* Unique post number for the current thread.
*
* For use within a `THREAD.POSTS_IN_PAGE` selector.
*/
NUMBER: "* ul.message-attribution-opposite > li > a:not([id])[rel=\"nofollow\"]",
/**
* Unique ID of the post in the F95Zone platform in the `id` attribute.
*
*
* For use within a `THREAD.POSTS_IN_PAGE` selector.
*/
ID: "span[id^=\"post\"]",
/**
* Unique ID of the post author in the `data-user-id` attribute.
*
*
* For use within a `THREAD.POSTS_IN_PAGE` selector.
*/
OWNER_ID: "* div.message-cell--user > * a[data-user-id]",
/**
* Main body of the post where the message written by the user is contained.
*
*
* For use within a `THREAD.POSTS_IN_PAGE` selector.
*/
BODY: "* article.message-body > div.bbWrapper",
/**
* Publication date of the post contained in the `datetime` attribute as an ISO date.
*
*
* For use within a `THREAD.POSTS_IN_PAGE` selector.
*/
PUBLISH_DATE: "* div.message-attribution-main > a > time",
/**
* Last modified date of the post contained in the `datetime` attribute as the ISO date.
*
*
* For use within a `THREAD.POSTS_IN_PAGE` selector.
*/
LAST_EDIT: "* div.message-lastEdit > time",
/**
* Gets the element only if the post has been bookmarked.
*
*
* For use within a `THREAD.POSTS_IN_PAGE` selector.
*/
BOOKMARKED: "* ul.message-attribution-opposite >li > a[title=\"Bookmark\"].is-bookmarked",
@ -152,37 +152,37 @@ export const POST = {
export const MEMBER = {
/**
* Name of the user.
*
*
* It also contains the unique ID of the user in the `data-user-id` attribute.
*/
NAME: "span[class^=\"username\"]",
/**
* Title of the user in the platform.
*
*
* i.e.: Member
*/
TITLE: "span.userTitle",
/**
* Avatar used by the user.
*
*
* Source in the attribute `src`.
*/
AVATAR: "span.avatarWrapper > a.avatar > img",
/**
* User assigned banners.
*
*
* The last element is always empty and can be ignored.
*/
BANNERS: "em.userBanner > strong",
/**
* Date the user joined the platform.
*
*
* The date is contained in the `datetime` attribute as an ISO string.
*/
JOINED: "div.uix_memberHeader__extra > div.memberHeader-blurb:nth-child(1) > * time",
/**
* Last time the user connected to the platform.
*
*
* The date is contained in the `datetime` attribute as an ISO string.
*/
LAST_SEEN: "div.uix_memberHeader__extra > div.memberHeader-blurb:nth-child(2) > * time",
@ -193,14 +193,14 @@ export const MEMBER = {
AMOUNT_DONATED: "div.pairJustifier > dl:nth-child(5) > dd",
/**
* Button used to follow/unfollow the user.
*
*
* If the text is `Unfollow` then the user is followed.
* If the text is `Follow` then the user is not followed.
*/
FOLLOWED: "div.memberHeader-buttons > div.buttonGroup:first-child > a[data-sk-follow] > span",
/**
* Button used to ignore/unignore the user.
*
*
* If the text is `Unignore` then the user is ignored.
* If the text is `Ignore` then the user is not ignored.
*/

View File

@ -8,8 +8,8 @@ export const urls = {
F95_LATEST_PHP: "https://f95zone.to/new_latest.php",
F95_BOOKMARKS: "https://f95zone.to/account/bookmarks",
/**
* Add the unique ID of the post to
* get the thread page where the post
* Add the unique ID of the post to
* get the thread page where the post
* is present.
*/
F95_POSTS: "https://f95zone.to/posts/",

View File

@ -9,7 +9,7 @@ import { urls as f95url } from "../constants/url.js";
* You *must* be logged.
* @param {LatestSearchQuery} query
* Query used for the search
* @param {Number} limit
* @param {Number} limit
* Maximum number of items to get. Default: 30
* @returns {Promise<String[]>} URLs of the handiworks
*/

View File

@ -43,7 +43,7 @@ interface ILatestResource {
//#region Public methods
/**
* Gets the basic data used for game data processing
* Gets the basic data used for game data processing
* (such as graphics engines and progress statuses)
*/
export default async function fetchPlatformData(): Promise<void> {
@ -106,7 +106,7 @@ function saveCache(path: string): void {
/**
* @private
* Given the HTML code of the response from the F95Zone,
* Given the HTML code of the response from the F95Zone,
* parse it and return the result.
*/
function parseLatestPlatformHTML(html: string): ILatestResource{

View File

@ -36,6 +36,6 @@ export default async function executeQuery(query: any, limit: number = 30): Prom
"handiwork");
// Fetch and return the urls
return await searchMap[key](query, limit);
return searchMap[key](query, limit);
}
//#endregion

View File

@ -25,7 +25,7 @@ export default async function fetchThreadHandiworkURLs(query: ThreadSearchQuery,
const response = await query.execute();
// Fetch the results from F95 and return the handiwork urls
if (response.isSuccess()) return await fetchResultURLs(response.value.data as string, limit);
if (response.isSuccess()) return fetchResultURLs(response.value.data as string, limit);
else throw response.value
}

View File

@ -15,7 +15,7 @@ import { failure, Result, success } from "./classes/result.js";
import { GenericAxiosError, InvalidF95Token, UnexpectedResponseContentType } from "./classes/errors.js";
// Global variables
const userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) " +
const userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) " +
"AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15";
// @ts-ignore
axiosCookieJarSupport.default(axios);
@ -61,15 +61,15 @@ export async function fetchHTML(url: string): Promise<Result<GenericAxiosError |
error: null
});
return isHTML ?
return isHTML ?
success(response.value.data as string) :
failure(unexpectedResponseError);
} else return failure(response.value as GenericAxiosError);
}
/**
* It authenticates to the platform using the credentials
* and token obtained previously. Save cookies on your
* It authenticates to the platform using the credentials
* and token obtained previously. Save cookies on your
* device after authentication.
* @param {module:./classes/credentials.ts:Credentials} credentials Platform access credentials
* @param {Boolean} force Specifies whether the request should be forced, ignoring any saved cookies
@ -173,7 +173,7 @@ export function isF95URL(url: string): boolean {
};
/**
* Checks if the string passed by parameter has a
* Checks if the string passed by parameter has a
* properly formatted and valid path to a URL (HTTP/HTTPS).
* @param {String} url String to check for correctness
*/
@ -187,7 +187,7 @@ export function isStringAValidURL(url: string): boolean {
/**
* Check if a particular URL is valid and reachable on the web.
* @param {string} url URL to check
* @param {boolean} [checkRedirect]
* @param {boolean} [checkRedirect]
* If true, the function will consider redirects a violation and return false.
* Default: false
* @returns {Promise<Boolean>} true if the URL exists, false otherwise

View File

@ -87,7 +87,7 @@ function toUpperCaseArray(a: string[]): string[] {
/**
* Check if the string `s` is in the dict `a`.
*
*
* Case insensitive.
*/
function stringInDict(s: string, a: TPrefixDict): boolean {
@ -99,7 +99,7 @@ function stringInDict(s: string, a: TPrefixDict): boolean {
/**
* Convert a string to a boolean.
*
*
* Check also for `yes`/`no` and `1`/`0`.
*/
function stringToBoolean(s: string): boolean {
@ -116,7 +116,7 @@ function stringToBoolean(s: string): boolean {
/**
* Gets the element with the given name or `undefined`.
*
*
* Case-insensitive.
*/
function getPostElementByName(elements: IPostElement[], name: string): IPostElement | undefined {
@ -127,7 +127,7 @@ function getPostElementByName(elements: IPostElement[], name: string): IPostElem
/**
* Parse the post prefixes.
*
*
* In particular, it elaborates the following prefixes for games:
* `Engine`, `Status`, `Mod`.
*/
@ -174,7 +174,7 @@ function fillWithPrefixes(hw: HandiWork, prefixes: string[]) {
/**
* Compiles a HandiWork object with the data extracted
* from the main post of the HandiWork page.
*
*
* The values that will be added are:
* `Overview`, `OS`, `Language`, `Version`, `Installation`,
* `Pages`, `Resolution`, `Lenght`, `Genre`, `Censored`,

View File

@ -21,11 +21,11 @@ export interface ILink extends IPostElement {
* Given a post of a thread page it extracts the information contained in the body.
*/
export function parseF95ThreadPost($: cheerio.Root, post: cheerio.Cheerio): IPostElement[] {
// The data is divided between "tag" and "text" elements.
// Simple data is composed of a "tag" element followed
// by a "text" element, while more complex data (contained
// in spoilers) is composed of a "tag" element, followed
// by a text containing only ":" and then by an additional
// The data is divided between "tag" and "text" elements.
// Simple data is composed of a "tag" element followed
// by a "text" element, while more complex data (contained
// in spoilers) is composed of a "tag" element, followed
// by a text containing only ":" and then by an additional
// "tag" element having as the first term "Spoiler"
// First fetch all the elements in the post
@ -44,13 +44,13 @@ export function parseF95ThreadPost($: cheerio.Root, post: cheerio.Cheerio): IPos
//#region Private methods
/**
* Process a spoiler element by getting its text broken
* Process a spoiler element by getting its text broken
* down by any other spoiler elements present.
*/
function parseCheerioSpoilerNode($: cheerio.Root, spoiler: cheerio.Cheerio): IPostElement {
// A spoiler block is composed of a div with class "bbCodeSpoiler",
// containing a div "bbCodeSpoiler-content" containing, in cascade,
// a div with class "bbCodeBlock--spoiler" and a div with class "bbCodeBlock-content".
// A spoiler block is composed of a div with class "bbCodeSpoiler",
// containing a div "bbCodeSpoiler-content" containing, in cascade,
// a div with class "bbCodeBlock--spoiler" and a div with class "bbCodeBlock-content".
// This last tag contains the required data.
// Local variables
@ -94,7 +94,7 @@ function parseCheerioSpoilerNode($: cheerio.Root, spoiler: cheerio.Cheerio): IPo
}
/**
* Check if the node passed as a parameter is of text type.
* Check if the node passed as a parameter is of text type.
* This also includes formatted nodes (i.e. `<b>`).
*/
function isTextNode(node: cheerio.Element): boolean {
@ -106,7 +106,7 @@ function isTextNode(node: cheerio.Element): boolean {
}
/**
* Gets the text of the node only, excluding child nodes.
* Gets the text of the node only, excluding child nodes.
* Also includes formatted text elements (i.e. `<b>`).
*/
function getCheerioNonChildrenText(node: cheerio.Cheerio): string {
@ -120,7 +120,7 @@ function getCheerioNonChildrenText(node: cheerio.Cheerio): string {
}
/**
* Process a node and see if it contains a
* Process a node and see if it contains a
* link or image. If not, it returns `null`.
*/
function parseCheerioLinkNode(element: cheerio.Cheerio): ILink | null {
@ -149,7 +149,7 @@ function parseCheerioLinkNode(element: cheerio.Cheerio): ILink | null {
}
/**
* Collapse an `IPostElement` element with a single subnode
* Collapse an `IPostElement` element with a single subnode
* in the `Content` field in case it has no information.
*/
function reducePostElement(element: IPostElement): IPostElement {
@ -234,7 +234,7 @@ function parseCheerioNode($: cheerio.Root, node: cheerio.Element, reduce = true)
}
/**
* It simplifies the `IPostElement` elements by associating
* It simplifies the `IPostElement` elements by associating
* the corresponding value to each characterizing element (i.e. author).
*/
function parsePostElements(elements: IPostElement[]): IPostElement[] {