From adf3aefcc5f7162703978c13264910f9c03d87bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A1ndor=20Levcs=C3=A1k?= Date: Wed, 11 Nov 2020 02:23:42 +0200 Subject: [PATCH] chore: add eslint package standard-with-typescript and apply rules --- .eslintrc | 29 +++++ cypress/.eslintrc | 16 +++ cypress/plugins/index.js | 2 - package.json | 35 +----- src/composable/useArticles.ts | 4 +- src/composable/useFollowProfile.ts | 2 +- src/composable/useProfile.ts | 2 +- src/config.ts | 1 + src/plugins/set-authorization-token.ts | 2 +- src/router.ts | 22 ++-- src/services/article/deleteArticle.ts | 2 +- src/services/article/getArticle.ts | 2 +- src/services/article/getArticles.ts | 10 +- src/services/article/postArticle.ts | 12 +- src/services/auth/postLogin.ts | 4 +- src/services/auth/postRegister.ts | 6 +- src/services/comment/getComments.ts | 2 +- src/services/comment/postComment.ts | 4 +- src/services/profile/getProfile.ts | 2 +- src/services/profile/putProfile.ts | 12 +- src/services/tag/getTags.ts | 2 +- src/shimes-vue.d.ts | 8 +- src/store/user.ts | 2 +- src/types/article.d.ts | 20 +-- src/types/comment.d.ts | 10 +- src/types/response.d.ts | 16 +-- src/types/user.d.ts | 20 +-- src/utils/create-async-process.spec.ts | 2 +- src/utils/create-async-process.ts | 2 +- src/utils/map-checkable-response.spec.ts | 2 +- src/utils/request.spec.ts | 36 +++--- src/utils/request.ts | 31 +++-- src/utils/storage.ts | 2 +- src/utils/test/mock-fetch.ts | 6 +- src/utils/test/wrap-tests.ts | 6 +- yarn.lock | 148 +++++++++-------------- 36 files changed, 237 insertions(+), 247 deletions(-) create mode 100644 .eslintrc create mode 100644 cypress/.eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..a1448ea --- /dev/null +++ b/.eslintrc @@ -0,0 +1,29 @@ +{ + "root": true, + "parser": "vue-eslint-parser", + "parserOptions": { + "parser": "@typescript-eslint/parser", + "project": "./tsconfig.json", + "sourceType": "module", + "extraFileExtensions": [ + ".vue", + ".d.ts" + ] + }, + "extends": [ + "standard", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "standard-with-typescript", + "plugin:vue/vue3-recommended" + ], + "rules": { + "no-undef": "off", + "comma-dangle": [ + "warn", + "always-multiline" + ], + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/promise-function-async": "off" + } +} \ No newline at end of file diff --git a/cypress/.eslintrc b/cypress/.eslintrc new file mode 100644 index 0000000..f7f4e24 --- /dev/null +++ b/cypress/.eslintrc @@ -0,0 +1,16 @@ +{ + "root": true, + "env": { + "cypress/globals": true + }, + "extends": [ + "standard", + "plugin:cypress/recommended" + ], + "rules": { + "comma-dangle": [ + "warn", + "always-multiline" + ] + } +} diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js index 225d017..aa9918d 100644 --- a/cypress/plugins/index.js +++ b/cypress/plugins/index.js @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ - /// // *********************************************************** // This example plugins/index.js can be used to load plugins diff --git a/package.json b/package.json index 58657e8..61406c1 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "dev": "vite", "build": "vite build", "check-ts-errors": "yarn tsc && yarn vti diagnostics", - "lint": "eslint \"{src,cypress/integration}/**/*.{js,ts,vue}\"", + "lint": "eslint \"{src,cypress}/**/*.{js,ts,vue}\"", "test:unit": "jest --coverage", "test:e2e": "cypress run", "test": "yarn check-ts-errors && yarn lint && yarn test:unit && yarn test:e2e" @@ -26,19 +26,20 @@ "@types/dompurify": "^2.0.4", "@types/jest": "^24.9.1", "@types/marked": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^4.6.1", - "@typescript-eslint/parser": "^4.6.1", + "@typescript-eslint/eslint-plugin": "^4.7.0", + "@typescript-eslint/parser": "^4.7.0", "@vue/compiler-sfc": "^3.0.2", "@vue/test-utils": "^2.0.0-beta.8", "babel-jest": "^24.9.0", "cypress": "^5.3.0", - "eslint": "^7.12.1", + "eslint": "^7.13.0", "eslint-config-standard": "^16.0.1", + "eslint-config-standard-with-typescript": "^19.0.1", "eslint-plugin-cypress": "^2.11.2", "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.2.1", - "eslint-plugin-standard": "^4.0.2", + "eslint-plugin-standard": "^4.1.0", "eslint-plugin-vue": "^7.1.0", "husky": "^4.3.0", "jest": "^24.9.0", @@ -60,30 +61,6 @@ "src/**/*.{ts,vue}": "eslint --fix", "cypress/**/*.js": "eslint --fix" }, - "eslintConfig": { - "parser": "vue-eslint-parser", - "parserOptions": { - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "./tsconfig.json" - }, - "sourceType": "module" - }, - "extends": [ - "standard", - "plugin:cypress/recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:vue/vue3-recommended" - ], - "rules": { - "no-undef": "off", - "comma-dangle": [ - "warn", - "always-multiline" - ] - } - }, "jest": { "preset": "ts-jest", "globals": { diff --git a/src/composable/useArticles.ts b/src/composable/useArticles.ts index 47d1c75..b38b761 100644 --- a/src/composable/useArticles.ts +++ b/src/composable/useArticles.ts @@ -59,9 +59,9 @@ export function useArticles () { const { active: articlesDownloading, run: runWrappedFetchArticles } = createAsyncProcess(fetchArticles) - watch(metaChanged, () => { + watch(metaChanged, async () => { if (page.value !== 1) changePage(1) - else runWrappedFetchArticles() + else await runWrappedFetchArticles() }) watch(page, runWrappedFetchArticles) diff --git a/src/composable/useFollowProfile.ts b/src/composable/useFollowProfile.ts index 0bd67e4..7aea25b 100644 --- a/src/composable/useFollowProfile.ts +++ b/src/composable/useFollowProfile.ts @@ -19,7 +19,7 @@ export function useFollow ({ username, following, onUpdate }: UseFollowProps) { async function toggleFollow () { let response: Either - if (following.value === true) { + if (following.value) { response = await deleteFollowProfile(username.value) } else { response = await postFollowProfile(username.value) diff --git a/src/composable/useProfile.ts b/src/composable/useProfile.ts index e8cdd94..d14987b 100644 --- a/src/composable/useProfile.ts +++ b/src/composable/useProfile.ts @@ -16,7 +16,7 @@ export function useProfile ({ username }: UseProfileProps) { updateProfile(profileData) } - async function updateProfile (profileData: Profile | null) { + function updateProfile (profileData: Profile | null) { profile.value = profileData } diff --git a/src/config.ts b/src/config.ts index ff629e1..9b239cb 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,3 +1,4 @@ export const CONFIG = { + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions API_HOST: import.meta.env.VITE_API_HOST || '', } diff --git a/src/plugins/set-authorization-token.ts b/src/plugins/set-authorization-token.ts index 75da951..c7419bd 100644 --- a/src/plugins/set-authorization-token.ts +++ b/src/plugins/set-authorization-token.ts @@ -3,5 +3,5 @@ import storage from '../utils/storage' export default function (): void { const token = storage.get('user')?.token - if (token) request.setAuthorizationHeader(token) + if (token !== undefined) request.setAuthorizationHeader(token) } diff --git a/src/router.ts b/src/router.ts index ce5904d..5375938 100644 --- a/src/router.ts +++ b/src/router.ts @@ -2,16 +2,16 @@ import { createRouter, createWebHashHistory, RouteParams } from 'vue-router' import Home from './pages/Home.vue' export type AppRouteNames = 'global-feed' - | 'my-feed' - | 'tag' - | 'article' - | 'create-article' - | 'edit-article' - | 'login' - | 'register' - | 'profile' - | 'profile-favorites' - | 'settings' +| 'my-feed' +| 'tag' +| 'article' +| 'create-article' +| 'edit-article' +| 'login' +| 'register' +| 'profile' +| 'profile-favorites' +| 'settings' export const router = createRouter({ history: createWebHashHistory(), @@ -75,6 +75,6 @@ export const router = createRouter({ }) export function routerPush (name: AppRouteNames, params?: RouteParams): ReturnType { - if (params) return router.push({ name, params }) + if (params !== undefined) return router.push({ name, params }) else return router.push({ name }) } diff --git a/src/services/article/deleteArticle.ts b/src/services/article/deleteArticle.ts index ef826f9..6427b91 100644 --- a/src/services/article/deleteArticle.ts +++ b/src/services/article/deleteArticle.ts @@ -1,5 +1,5 @@ import { request } from '../index' -export async function deleteArticle (slug: string): Promise { +export function deleteArticle (slug: string): Promise { return request.delete(`/articles/${slug}`) } diff --git a/src/services/article/getArticle.ts b/src/services/article/getArticle.ts index 5e3a5d7..a4c5483 100644 --- a/src/services/article/getArticle.ts +++ b/src/services/article/getArticle.ts @@ -1,5 +1,5 @@ import { request } from '../index' -export async function getArticle (slug: string): Promise
{ +export function getArticle (slug: string): Promise
{ return request.get(`/articles/${slug}`).then(res => res.article) } diff --git a/src/services/article/getArticles.ts b/src/services/article/getArticles.ts index bf0904d..950ea2b 100644 --- a/src/services/article/getArticles.ts +++ b/src/services/article/getArticles.ts @@ -1,26 +1,26 @@ import { limit, request } from '../index' -export async function getArticles (page = 1): Promise { +export function getArticles (page = 1): Promise { const params = { limit, offset: (page - 1) * limit } return request.get('/articles', { params }) } -export async function getFavoritedArticles (username: string, page = 1): Promise { +export function getFavoritedArticles (username: string, page = 1): Promise { const params = { limit, offset: (page - 1) * limit, favorited: username } return request.get('/articles', { params }) } -export async function getProfileArticles (username: string, page = 1): Promise { +export function getProfileArticles (username: string, page = 1): Promise { const params = { limit, offset: (page - 1) * limit, author: username } return request.get('/articles', { params }) } -export async function getFeeds (page = 1): Promise { +export function getFeeds (page = 1): Promise { const params = { limit, offset: (page - 1) * limit } return request.get('/articles/feed', { params }) } -export async function getArticlesByTag (tagName: string, page = 1): Promise { +export function getArticlesByTag (tagName: string, page = 1): Promise { const params = { tag: tagName, limit, offset: (page - 1) * limit } return request.get('/articles', { params }) } diff --git a/src/services/article/postArticle.ts b/src/services/article/postArticle.ts index c1ac3c5..9707ed0 100644 --- a/src/services/article/postArticle.ts +++ b/src/services/article/postArticle.ts @@ -1,18 +1,18 @@ import { request } from '../index' interface PostArticleForm { - title: string; - description: string; - body: string; - tagList: string[]; + title: string + description: string + body: string + tagList: string[] } -export async function postArticle (form: PostArticleForm): Promise
{ +export function postArticle (form: PostArticleForm): Promise
{ return request.post('/articles', { article: form }) .then(res => res.article) } -export async function putArticle (slug: string, form: PostArticleForm): Promise
{ +export function putArticle (slug: string, form: PostArticleForm): Promise
{ return request.put(`/articles/${slug}`, { article: form }) .then(res => res.article) } diff --git a/src/services/auth/postLogin.ts b/src/services/auth/postLogin.ts index 88f7300..c5dc286 100644 --- a/src/services/auth/postLogin.ts +++ b/src/services/auth/postLogin.ts @@ -6,8 +6,8 @@ import { mapValidationResponse } from '../../utils/map-checkable-response' import { Either, fail, success } from '../../utils/either' export interface PostLoginForm { - email: string; - password: string; + email: string + password: string } export type PostLoginErrors = Partial> diff --git a/src/services/auth/postRegister.ts b/src/services/auth/postRegister.ts index 859705f..da03b85 100644 --- a/src/services/auth/postRegister.ts +++ b/src/services/auth/postRegister.ts @@ -6,9 +6,9 @@ import { mapValidationResponse } from '../../utils/map-checkable-response' import { Either, fail, success } from '../../utils/either' export interface PostRegisterForm { - email: string; - password: string; - username: string; + email: string + password: string + username: string } export type PostRegisterErrors = Partial> diff --git a/src/services/comment/getComments.ts b/src/services/comment/getComments.ts index 4badd12..5d26536 100644 --- a/src/services/comment/getComments.ts +++ b/src/services/comment/getComments.ts @@ -1,5 +1,5 @@ import { request } from '../index' -export async function getCommentsByArticle (slug: string): Promise { +export function getCommentsByArticle (slug: string): Promise { return request.get(`/articles/${slug}/comments`).then(res => res.comments) } diff --git a/src/services/comment/postComment.ts b/src/services/comment/postComment.ts index 4c7cea9..86ecbc6 100644 --- a/src/services/comment/postComment.ts +++ b/src/services/comment/postComment.ts @@ -1,10 +1,10 @@ import { request } from '../index' -export async function deleteComment (slug: string, commentId: number): Promise> { +export function deleteComment (slug: string, commentId: number): Promise> { return request.delete(`/articles/${slug}/comments/${commentId}`) } -export async function postComment (slug: string, body: string): Promise { +export function postComment (slug: string, body: string): Promise { return request.post(`/articles/${slug}/comments`, { comment: { body } }) .then(res => res.comment) } diff --git a/src/services/profile/getProfile.ts b/src/services/profile/getProfile.ts index c74f227..742f12e 100644 --- a/src/services/profile/getProfile.ts +++ b/src/services/profile/getProfile.ts @@ -1,5 +1,5 @@ import { request } from '../index' -export async function getProfile (username: string): Promise { +export function getProfile (username: string): Promise { return request.get(`/profiles/${username}`).then(res => res.profile) } diff --git a/src/services/profile/putProfile.ts b/src/services/profile/putProfile.ts index 6de9bfa..0b32aec 100644 --- a/src/services/profile/putProfile.ts +++ b/src/services/profile/putProfile.ts @@ -1,13 +1,13 @@ import { request } from '../index' export interface PutProfileForm { - username?: string; - bio?: string; - image?: string; - email?: string; - password?: string; + username?: string + bio?: string + image?: string + email?: string + password?: string } -export async function putProfile (form: PutProfileForm): Promise { +export function putProfile (form: PutProfileForm): Promise { return request.put('/user', form).then(res => res.user) } diff --git a/src/services/tag/getTags.ts b/src/services/tag/getTags.ts index 9934c24..1c13211 100644 --- a/src/services/tag/getTags.ts +++ b/src/services/tag/getTags.ts @@ -1,5 +1,5 @@ import { request } from '../index' -export async function getAllTags (): Promise { +export function getAllTags (): Promise { return request.get('/tags').then(res => res.tags) } diff --git a/src/shimes-vue.d.ts b/src/shimes-vue.d.ts index 8a7a816..354e766 100644 --- a/src/shimes-vue.d.ts +++ b/src/shimes-vue.d.ts @@ -5,8 +5,8 @@ declare module '*.vue' { export default Component } - interface ImportMeta { - env: { - VITE_API_HOST: string - } +interface ImportMeta { + env: { + VITE_API_HOST: string } +} diff --git a/src/store/user.ts b/src/store/user.ts index b7326cc..6e3cb32 100644 --- a/src/store/user.ts +++ b/src/store/user.ts @@ -23,7 +23,7 @@ export const checkAuthorization = (user: ComputedRef): user is Comp } export const updateUser = mutation('updateUser', (state, userData) => { - if (!userData) { + if (userData === undefined || userData === null) { storage.remove('user') request.deleteAuthorizationHeader() state.user = null diff --git a/src/types/article.d.ts b/src/types/article.d.ts index 85d25e7..7ffacf1 100644 --- a/src/types/article.d.ts +++ b/src/types/article.d.ts @@ -1,12 +1,12 @@ declare interface Article { - title: string; - slug: string; - body: string; - createdAt: string; - updatedAt: string; - tagList: string[]; - description: string; - author: Profile; - favorited: boolean; - favoritesCount: number; + title: string + slug: string + body: string + createdAt: string + updatedAt: string + tagList: string[] + description: string + author: Profile + favorited: boolean + favoritesCount: number } diff --git a/src/types/comment.d.ts b/src/types/comment.d.ts index 6998746..6aa304e 100644 --- a/src/types/comment.d.ts +++ b/src/types/comment.d.ts @@ -1,7 +1,7 @@ declare interface ArticleComment { - id: number; - createdAt: string; - updatedAt: string; - body: string; - author: Profile; + id: number + createdAt: string + updatedAt: string + body: string + author: Profile } diff --git a/src/types/response.d.ts b/src/types/response.d.ts index 21fcece..4ad9aae 100644 --- a/src/types/response.d.ts +++ b/src/types/response.d.ts @@ -1,28 +1,28 @@ declare interface UserResponse { - user: User; + user: User } declare interface TagsResponse { - tags: string[]; + tags: string[] } declare interface ProfileResponse { - profile: Profile; + profile: Profile } declare interface ArticleResponse { - article: Article; + article: Article } declare interface ArticlesResponse { - articles: Article[]; - articlesCount: number; + articles: Article[] + articlesCount: number } declare interface CommentResponse { - comment: ArticleComment; + comment: ArticleComment } declare interface CommentsResponse { - comments: ArticleComment[]; + comments: ArticleComment[] } diff --git a/src/types/user.d.ts b/src/types/user.d.ts index 1c652df..ccd73f7 100644 --- a/src/types/user.d.ts +++ b/src/types/user.d.ts @@ -1,15 +1,15 @@ declare interface Profile { - username: string; - bio: string; - image: string; - following: boolean; + username: string + bio: string + image: string + following: boolean } declare interface User { - id: number; - email: string; - username: string; - bio: string | undefined; - image: string | undefined; - token: string; + id: number + email: string + username: string + bio: string | undefined + image: string | undefined + token: string } diff --git a/src/utils/create-async-process.spec.ts b/src/utils/create-async-process.spec.ts index 31ef13c..504fdd7 100644 --- a/src/utils/create-async-process.spec.ts +++ b/src/utils/create-async-process.spec.ts @@ -2,7 +2,7 @@ import { isRef } from 'vue' import createAsyncProcess from './create-async-process' describe('# Create async process', function () { - const someProcess = async () => Promise.resolve(null) + const someProcess = () => Promise.resolve(null) it('should expect active as Vue Ref type', function () { const { active } = createAsyncProcess(someProcess) diff --git a/src/utils/create-async-process.ts b/src/utils/create-async-process.ts index bc604e4..4c98e0a 100644 --- a/src/utils/create-async-process.ts +++ b/src/utils/create-async-process.ts @@ -3,7 +3,7 @@ import { Ref, ref } from 'vue' // eslint-disable-next-line @typescript-eslint/no-explicit-any interface CreateAsyncProcessReturn any> { active: Ref - run: (...args : Parameters) => Promise> + run: (...args: Parameters) => Promise> } // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/utils/map-checkable-response.spec.ts b/src/utils/map-checkable-response.spec.ts index b20d994..9dae919 100644 --- a/src/utils/map-checkable-response.spec.ts +++ b/src/utils/map-checkable-response.spec.ts @@ -2,7 +2,7 @@ import { ValidationError, AuthorizationError, NetworkError } from 'src/types/err import { Either, fail, isEither, success } from './either' import { mapAuthorizationResponse, mapValidationResponse } from './map-checkable-response' -const createCheckableResponse = (response: Partial): Either> => response.ok +const createCheckableResponse = (response: Partial): Either> => response.ok === true ? success(response) : fail(new NetworkError(response as Response)) diff --git a/src/utils/request.spec.ts b/src/utils/request.spec.ts index 3cd0560..3a8f952 100644 --- a/src/utils/request.spec.ts +++ b/src/utils/request.spec.ts @@ -52,7 +52,7 @@ async function triggerMethod (request: FetchRequest, method: Method } } -function forCorrectMethods (task: string, fn: (method: Method) => void): void { +function forCorrectMethods (task: string, fn: (method: Method) => Promise): void { wrapTests({ task, fn, @@ -61,7 +61,7 @@ function forCorrectMethods (task: string, fn: (method: Method) => void): void { }) } -function forCheckableMethods (task: string, fn: (method: CheckableMethod) => void): void { +function forCheckableMethods (task: string, fn: (method: CheckableMethod) => Promise): void { wrapTests({ task, fn, @@ -70,7 +70,7 @@ function forCheckableMethods (task: string, fn: (method: CheckableMethod) => voi }) } -function forAllMethods (task: string, fn: (method: Method | CheckableMethod) => void): void { +function forAllMethods (task: string, fn: (method: Method | CheckableMethod) => Promise): void { forCheckableMethods(task, fn) forCorrectMethods(task, fn) } @@ -78,7 +78,7 @@ function forAllMethods (task: string, fn: (method: Method | CheckableMethod) => forAllMethods('# Should be implemented', async (method) => { const request = new FetchRequest() - triggerMethod(request, method) + await triggerMethod(request, method) expect(global.fetch).toBeCalledWith(PATH, expect.objectContaining({ method: method.replace('checkable', '').toUpperCase(), @@ -89,7 +89,7 @@ describe('# Should implement prefix', () => { forAllMethods('should implement global prefix', async (method) => { const request = new FetchRequest({ prefix: PREFIX }) - triggerMethod(request, method) + await triggerMethod(request, method) expect(global.fetch).toBeCalledWith(`${PREFIX}${PATH}`, expect.any(Object)) }) @@ -97,7 +97,7 @@ describe('# Should implement prefix', () => { forAllMethods('should implement local prefix', async (method) => { const request = new FetchRequest() - triggerMethod(request, method, { prefix: SUB_PREFIX }) + await triggerMethod(request, method, { prefix: SUB_PREFIX }) expect(global.fetch).toBeCalledWith(`${SUB_PREFIX}${PATH}`, expect.any(Object)) }) @@ -105,7 +105,7 @@ describe('# Should implement prefix', () => { forAllMethods('should implement global + local prefix', async (method) => { const request = new FetchRequest({ prefix: PREFIX }) - triggerMethod(request, method, { prefix: SUB_PREFIX }) + await triggerMethod(request, method, { prefix: SUB_PREFIX }) expect(global.fetch).toBeCalledWith(`${SUB_PREFIX}${PATH}`, expect.any(Object)) }) @@ -115,7 +115,7 @@ describe('# Should convert query object to query string in request url', () => { forAllMethods('should implement global query', async (method) => { const request = new FetchRequest({ params: PARAMS }) - triggerMethod(request, method) + await triggerMethod(request, method) expect(global.fetch).toBeCalledWith(`${PATH}?${params2query(PARAMS)}`, expect.any(Object)) }) @@ -123,7 +123,7 @@ describe('# Should convert query object to query string in request url', () => { forAllMethods('should implement local query', async (method) => { const request = new FetchRequest() - triggerMethod(request, method, { params: PARAMS }) + await triggerMethod(request, method, { params: PARAMS }) expect(global.fetch).toBeCalledWith(`${PATH}?${params2query(PARAMS)}`, expect.any(Object)) }) @@ -134,7 +134,7 @@ describe('# Should convert query object to query string in request url', () => { const expectedOptions = { params: { q1: 'q11', q2: 'q2', q3: 'q3' } } const request = new FetchRequest(options) - triggerMethod(request, method, localOptions) + await triggerMethod(request, method, localOptions) expect(global.fetch).toBeCalledWith(`${PATH}?${params2query(expectedOptions.params)}`, expect.any(Object)) }) @@ -174,15 +174,15 @@ forCorrectMethods('# Should converted correct response body to json', async func forCheckableMethods('# Should converted checkable response to Either', async function (method) { const DATA = { foo: 'bar' } - type DATA_TYPE = {foo: 'bar'} + interface DATA_TYPE { foo: 'bar' } mockFetch({ type: 'body', ...DATA }) const request = new FetchRequest() const result = await triggerMethod(request, method) - const resultIsEither = isEither(result) - const resultIsOk = isEither(result) && result.isOk() - const resultValue = isEither(result) && result.isOk() ? result.value : null + const resultIsEither = isEither(result) + const resultIsOk = isEither(result) && result.isOk() + const resultValue = isEither(result) && result.isOk() ? result.value : null expect(resultIsEither).toBe(true) expect(resultIsOk).toBe(true) @@ -216,9 +216,9 @@ forCheckableMethods('# Should return Either if checkabl const request = new FetchRequest() const result = await triggerMethod(request, method) - const resultIsEither = isEither(result) - const resultIsNotOk = isEither(result) && result.isFail() - const resultValue = isEither(result) && result.isFail() ? result.value : null + const resultIsEither = isEither(result) + const resultIsNotOk = isEither(result) && result.isFail() + const resultValue = isEither(result) && result.isFail() ? result.value : null expect(resultIsEither).toBe(true) expect(resultIsNotOk).toBe(true) @@ -233,7 +233,7 @@ describe('# Authorization header', function () { const request = new FetchRequest() request.setAuthorizationHeader(TOKEN) - triggerMethod(request, method) + await triggerMethod(request, method) expect(global.fetch).toBeCalledWith(PATH, expect.objectContaining(OPTIONS)) }) diff --git a/src/utils/request.ts b/src/utils/request.ts index 6500bb3..6f91f43 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -6,39 +6,39 @@ import { Either, fail, success } from './either' import params2query from './params-to-query' export interface FetchRequestOptions { - prefix: string; - headers: Record; - params: Record; + prefix: string + headers: Record + params: Record } export default class FetchRequest { - private defaultOptions: FetchRequestOptions = { + private readonly defaultOptions: FetchRequestOptions = { prefix: '', headers: {}, params: {}, } - private options: FetchRequestOptions + private readonly options: FetchRequestOptions constructor (options: Partial = {}) { this.options = merge(this.defaultOptions, options) } - private generateFinalUrl = (url: string, options: Partial = {}) => { + private readonly generateFinalUrl = (url: string, options: Partial = {}) => { const prefix = options.prefix ?? this.options.prefix const params = merge(this.options.params, options.params ?? {}) let finalUrl = `${prefix}${url}` - if (Object.keys(params).length) finalUrl += `?${params2query(params)}` + if (Object.keys(params).length > 0) finalUrl += `?${params2query(params)}` return finalUrl } - private generateFinalHeaders = (options: Partial = {}) => { + private readonly generateFinalHeaders = (options: Partial = {}) => { return merge(this.options.headers, options.headers ?? {}) } - private handleResponse = (response: Response): Promise> => { + private readonly handleResponse = (response: Response): Promise> => { if (response.ok) { return response.json().then(json => success(json as T)) } @@ -46,7 +46,7 @@ export default class FetchRequest { return Promise.resolve(fail(new NetworkError(response))) } - private handleCorrectResponse = (response: Response): Promise => { + private readonly handleCorrectResponse = (response: Response): Promise => { if (response.ok) { return response.json() } @@ -55,9 +55,9 @@ export default class FetchRequest { } private runFetch ({ method, url, data, options }: { - method: 'GET' | 'DELETE' | 'POST' | 'PUT' | 'PATCH', - url: string, - data?: unknown, + method: 'GET' | 'DELETE' | 'POST' | 'PUT' | 'PATCH' + url: string + data?: unknown options?: Partial }) { const finalUrl = this.generateFinalUrl(url, options) @@ -65,7 +65,7 @@ export default class FetchRequest { // eslint-disable-next-line @typescript-eslint/no-explicit-any const fetchOptions: any = { method, headers } - if (data) fetchOptions.body = JSON.stringify(data) + if (data !== undefined) fetchOptions.body = JSON.stringify(data) return fetch(finalUrl, fetchOptions) } @@ -118,8 +118,7 @@ export default class FetchRequest { } public setAuthorizationHeader (token: string): void { - if (!this.options.headers) this.options.headers = {} - if (token) this.options.headers.Authorization = `Token ${token}` + if (token !== '') this.options.headers.Authorization = `Token ${token}` } public deleteAuthorizationHeader (): void { diff --git a/src/utils/storage.ts b/src/utils/storage.ts index e3dc84a..1d3ff81 100644 --- a/src/utils/storage.ts +++ b/src/utils/storage.ts @@ -1,6 +1,6 @@ function get (key: string): T | null { try { - const value = localStorage.getItem(key) || '' + const value = localStorage.getItem(key) ?? '' return JSON.parse(value) } catch (e) { return null diff --git a/src/utils/test/mock-fetch.ts b/src/utils/test/mock-fetch.ts index 67a9715..ec08db9 100644 --- a/src/utils/test/mock-fetch.ts +++ b/src/utils/test/mock-fetch.ts @@ -3,9 +3,9 @@ interface FetchResponseBody { } interface FetchResponseFull { type: 'full' - ok: boolean, - status: number, - statusText:string + ok: boolean + status: number + statusText: string json: () => Promise } diff --git a/src/utils/test/wrap-tests.ts b/src/utils/test/wrap-tests.ts index 60ddf04..0ef5f5b 100644 --- a/src/utils/test/wrap-tests.ts +++ b/src/utils/test/wrap-tests.ts @@ -1,8 +1,8 @@ interface WrapTestsProps { task: string list: Item[] - fn: (item: Item) => void, - only?: boolean, + fn: (item: Item) => void + only?: boolean testName?: (item: Item, index: number) => string } @@ -11,7 +11,7 @@ function wrapTests ({ task, list, fn, testName, only = false }: WrapTestsP descFn(task, () => { list.forEach((item, index) => { - const name = testName ? testName(item, index) : '' + const name = testName !== undefined ? testName(item, index) : '' it(name, () => fn(item)) }) }) diff --git a/yarn.lock b/yarn.lock index e963424..425b529 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1151,13 +1151,13 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^4.6.1": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.6.1.tgz#99d77eb7a016fd5a5e749d2c44a7e4c317eb7da3" - integrity sha512-SNZyflefTMK2JyrPfFFzzoy2asLmZvZJ6+/L5cIqg4HfKGiW2Gr1Go1OyEVqne/U4QwmoasuMwppoBHWBWF2nA== +"@typescript-eslint/eslint-plugin@^4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.7.0.tgz#85c9bbda00c0cb604d3c241f7bc7fb171a2d3479" + integrity sha512-li9aiSVBBd7kU5VlQlT1AqP0uWGDK6JYKUQ9cVDnOg34VNnd9t4jr0Yqc/bKxJr/tDCPDaB4KzoSFN9fgVxe/Q== dependencies: - "@typescript-eslint/experimental-utils" "4.6.1" - "@typescript-eslint/scope-manager" "4.6.1" + "@typescript-eslint/experimental-utils" "4.7.0" + "@typescript-eslint/scope-manager" "4.7.0" debug "^4.1.1" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" @@ -1175,15 +1175,15 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/experimental-utils@4.6.1": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.6.1.tgz#a9c691dfd530a9570274fe68907c24c07a06c4aa" - integrity sha512-qyPqCFWlHZXkEBoV56UxHSoXW2qnTr4JrWVXOh3soBP3q0o7p4pUEMfInDwIa0dB/ypdtm7gLOS0hg0a73ijfg== +"@typescript-eslint/experimental-utils@4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.7.0.tgz#8d1058c38bec3d3bbd9c898a1c32318d80faf3c5" + integrity sha512-cymzovXAiD4EF+YoHAB5Oh02MpnXjvyaOb+v+BdpY7lsJXZQN34oIETeUwVT2XfV9rSNpXaIcknDLfupO/tUoA== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.6.1" - "@typescript-eslint/types" "4.6.1" - "@typescript-eslint/typescript-estree" "4.6.1" + "@typescript-eslint/scope-manager" "4.7.0" + "@typescript-eslint/types" "4.7.0" + "@typescript-eslint/typescript-estree" "4.7.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" @@ -1198,33 +1198,33 @@ "@typescript-eslint/typescript-estree" "3.10.1" eslint-visitor-keys "^1.1.0" -"@typescript-eslint/parser@^4.6.1": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.6.1.tgz#b801bff67b536ecc4a840ac9289ba2be57e02428" - integrity sha512-lScKRPt1wM9UwyKkGKyQDqf0bh6jm8DQ5iN37urRIXDm16GEv+HGEmum2Fc423xlk5NUOkOpfTnKZc/tqKZkDQ== +"@typescript-eslint/parser@^4.0.0", "@typescript-eslint/parser@^4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.7.0.tgz#44bdab0f788b478178368baa65d3365fdc63da1c" + integrity sha512-+meGV8bMP1sJHBI2AFq1GeTwofcGiur8LoIr6v+rEmD9knyCqDlrQcFHR0KDDfldHIFDU/enZ53fla6ReF4wRw== dependencies: - "@typescript-eslint/scope-manager" "4.6.1" - "@typescript-eslint/types" "4.6.1" - "@typescript-eslint/typescript-estree" "4.6.1" + "@typescript-eslint/scope-manager" "4.7.0" + "@typescript-eslint/types" "4.7.0" + "@typescript-eslint/typescript-estree" "4.7.0" debug "^4.1.1" -"@typescript-eslint/scope-manager@4.6.1": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.6.1.tgz#21872b91cbf7adfc7083f17b8041149148baf992" - integrity sha512-f95+80r6VdINYscJY1KDUEDcxZ3prAWHulL4qRDfNVD0I5QAVSGqFkwHERDoLYJJWmEAkUMdQVvx7/c2Hp+Bjg== +"@typescript-eslint/scope-manager@4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.7.0.tgz#2115526085fb72723ccdc1eeae75dec7126220ed" + integrity sha512-ILITvqwDJYbcDCROj6+Ob0oCKNg3SH46iWcNcTIT9B5aiVssoTYkhKjxOMNzR1F7WSJkik4zmuqve5MdnA0DyA== dependencies: - "@typescript-eslint/types" "4.6.1" - "@typescript-eslint/visitor-keys" "4.6.1" + "@typescript-eslint/types" "4.7.0" + "@typescript-eslint/visitor-keys" "4.7.0" "@typescript-eslint/types@3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" integrity sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ== -"@typescript-eslint/types@4.6.1": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.6.1.tgz#d3ad7478f53f22e7339dc006ab61aac131231552" - integrity sha512-k2ZCHhJ96YZyPIsykickez+OMHkz06xppVLfJ+DY90i532/Cx2Z+HiRMH8YZQo7a4zVd/TwNBuRCdXlGK4yo8w== +"@typescript-eslint/types@4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.7.0.tgz#5e95ef5c740f43d942542b35811f87b62fccca69" + integrity sha512-uLszFe0wExJc+I7q0Z/+BnP7wao/kzX0hB5vJn4LIgrfrMLgnB2UXoReV19lkJQS1a1mHWGGODSxnBx6JQC3Sg== "@typescript-eslint/typescript-estree@3.10.1": version "3.10.1" @@ -1240,13 +1240,13 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@4.6.1": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.6.1.tgz#6025cce724329413f57e4959b2d676fceeca246f" - integrity sha512-/J/kxiyjQQKqEr5kuKLNQ1Finpfb8gf/NpbwqFFYEBjxOsZ621r9AqwS9UDRA1Rrr/eneX/YsbPAIhU2rFLjXQ== +"@typescript-eslint/typescript-estree@4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.7.0.tgz#539531167f05ba20eb0b6785567076679e29d393" + integrity sha512-5XZRQznD1MfUmxu1t8/j2Af4OxbA7EFU2rbo0No7meb46eHgGkSieFdfV6omiC/DGIBhH9H9gXn7okBbVOm8jw== dependencies: - "@typescript-eslint/types" "4.6.1" - "@typescript-eslint/visitor-keys" "4.6.1" + "@typescript-eslint/types" "4.7.0" + "@typescript-eslint/visitor-keys" "4.7.0" debug "^4.1.1" globby "^11.0.1" is-glob "^4.0.1" @@ -1261,12 +1261,12 @@ dependencies: eslint-visitor-keys "^1.1.0" -"@typescript-eslint/visitor-keys@4.6.1": - version "4.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.6.1.tgz#6b125883402d8939df7b54528d879e88f7ba3614" - integrity sha512-owABze4toX7QXwOLT3/D5a8NecZEjEWU1srqxENTfqsY3bwVnl3YYbOh6s1rp2wQKO9RTHFGjKes08FgE7SVMw== +"@typescript-eslint/visitor-keys@4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.7.0.tgz#6783824f22acfc49e754970ed21b88ac03b80e6f" + integrity sha512-aDJDWuCRsf1lXOtignlfiPODkzSxxop7D0rZ91L6ZuMlcMCSh0YyK+gAfo5zN/ih6WxMwhoXgJWC3cWQdaKC+A== dependencies: - "@typescript-eslint/types" "4.6.1" + "@typescript-eslint/types" "4.7.0" eslint-visitor-keys "^2.0.0" "@vue/compiler-core@3.0.2": @@ -3079,6 +3079,19 @@ escodegen@^1.14.1, escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" +eslint-config-standard-with-typescript@^19.0.1: + version "19.0.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-19.0.1.tgz#d486e08a82f6bf43a8e0ef1bc76088e26fe7a587" + integrity sha512-hAKj81+f4a+9lnvpHwZ4XSL672CbwSe5UJ7fTdL/RsQdqs4IjHudMETZuNQwwU7NlYpBTF9se7FRf5Pp7CVdag== + dependencies: + "@typescript-eslint/parser" "^4.0.0" + eslint-config-standard "^14.1.1" + +eslint-config-standard@^14.1.1: + version "14.1.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" + integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg== + eslint-config-standard@^16.0.1: version "16.0.1" resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-16.0.1.tgz#9a385eea27f96b7918cb53f07e01e9d10cc56401" @@ -3151,10 +3164,10 @@ eslint-plugin-promise@^4.2.1: resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a" integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw== -eslint-plugin-standard@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.2.tgz#021211a9f077e63a6847e7bb9ab4247327ac8e0c" - integrity sha512-nKptN8l7jksXkwFk++PhJB3cCDTcXOEyhISIN86Ue2feJ1LFyY3PrY3/xT2keXlJSY5bpmbiTG0f885/YKAvTA== +eslint-plugin-standard@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.1.0.tgz#0c3bf3a67e853f8bbbc580fb4945fbf16f41b7c5" + integrity sha512-ZL7+QRixjTR6/528YNGyDotyffm5OQst/sGxKDwGb9Uqs4In5Egi4+jbobhqJoyoCM6/7v/1A5fhQ7ScMtDjaQ== eslint-plugin-vue@^7.1.0: version "7.1.0" @@ -3241,7 +3254,7 @@ eslint@^6.8.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -eslint@^7.11.0: +eslint@^7.11.0, eslint@^7.13.0: version "7.13.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.13.0.tgz#7f180126c0dcdef327bfb54b211d7802decc08da" integrity sha512-uCORMuOO8tUzJmsdRtrvcGq5qposf7Rw0LwkTJkoDbOycVQtQjmnhZSuLQnozLE4TmAzlMVV45eCHmQ1OpDKUQ== @@ -3284,49 +3297,6 @@ eslint@^7.11.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -eslint@^7.12.1: - version "7.12.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.12.1.tgz#bd9a81fa67a6cfd51656cdb88812ce49ccec5801" - integrity sha512-HlMTEdr/LicJfN08LB3nM1rRYliDXOmfoO4vj39xN6BLpFzF00hbwBoqHk8UcJ2M/3nlARZWy/mslvGEuZFvsg== - dependencies: - "@babel/code-frame" "^7.0.0" - "@eslint/eslintrc" "^0.2.1" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.0" - esquery "^1.2.0" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash "^4.17.19" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - espree@^6.1.2, espree@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a"