mirror of
https://github.com/apricote/Listory.git
synced 2026-01-13 13:11:02 +00:00
chore(lint): switch to eslint
This commit is contained in:
parent
f56548e432
commit
9b96d0fab4
29 changed files with 1609 additions and 113 deletions
43
.eslintrc.js
Normal file
43
.eslintrc.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
module.exports = {
|
||||
extends: ["airbnb-typescript", "prettier"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: "tsconfig.json",
|
||||
},
|
||||
plugins: [
|
||||
"eslint-plugin-import",
|
||||
"eslint-plugin-jsdoc",
|
||||
"eslint-plugin-prefer-arrow",
|
||||
"eslint-plugin-react",
|
||||
"@typescript-eslint",
|
||||
],
|
||||
rules: {
|
||||
"import/prefer-default-export": "off",
|
||||
"class-methods-use-this": "off",
|
||||
"@typescript-eslint/lines-between-class-members": [
|
||||
"error",
|
||||
"always",
|
||||
{ exceptAfterSingleLine: true },
|
||||
],
|
||||
"@typescript-eslint/return-await": "off",
|
||||
"import/no-cycle": "off",
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
{
|
||||
selector: "ForInStatement",
|
||||
message:
|
||||
"for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.",
|
||||
},
|
||||
{
|
||||
selector: "LabeledStatement",
|
||||
message:
|
||||
"Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.",
|
||||
},
|
||||
{
|
||||
selector: "WithStatement",
|
||||
message:
|
||||
"`with` is disallowed in strict mode because it makes code impossible to predict and optimize.",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -54,6 +54,7 @@ function useProvideAuth(): AuthContext {
|
|||
|
||||
useEffect(() => {
|
||||
refreshAccessToken().catch(() => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("Unable to refresh access token");
|
||||
});
|
||||
}, [refreshAccessToken]);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable no-console */
|
||||
// This optional code is used to register a service worker.
|
||||
// register() is not called by default.
|
||||
|
||||
|
|
|
|||
1550
package-lock.json
generated
1550
package-lock.json
generated
File diff suppressed because it is too large
Load diff
16
package.json
16
package.json
|
|
@ -15,7 +15,7 @@
|
|||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"lint": "tslint -p tsconfig.json -c tslint.json",
|
||||
"lint": "eslint --ext .js,.jsx,.ts,.tsx src/ frontend/src/",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
|
|
@ -64,6 +64,17 @@
|
|||
"@types/node": "15.6.0",
|
||||
"@types/passport-jwt": "3.0.5",
|
||||
"@types/supertest": "2.0.11",
|
||||
"@typescript-eslint/eslint-plugin": "4.25.0",
|
||||
"@typescript-eslint/parser": "4.25.0",
|
||||
"eslint": "7.27.0",
|
||||
"eslint-config-airbnb-typescript": "12.3.1",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-import": "2.23.3",
|
||||
"eslint-plugin-jsdoc": "35.0.0",
|
||||
"eslint-plugin-jsx-a11y": "6.4.1",
|
||||
"eslint-plugin-prefer-arrow": "1.2.3",
|
||||
"eslint-plugin-react": "7.23.2",
|
||||
"eslint-plugin-react-hooks": "4.2.0",
|
||||
"jest": "26.6.3",
|
||||
"prettier": "2.3.0",
|
||||
"supertest": "6.1.3",
|
||||
|
|
@ -71,9 +82,6 @@
|
|||
"ts-loader": "9.2.2",
|
||||
"ts-node": "10.0.0",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"tslint": "6.1.3",
|
||||
"tslint-config-prettier": "1.18.0",
|
||||
"tslint-plugin-prettier": "2.3.0",
|
||||
"typescript": "4.2.4"
|
||||
},
|
||||
"jest": {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export class AuthSession {
|
|||
@PrimaryGeneratedColumn("uuid")
|
||||
id: string;
|
||||
|
||||
@ManyToOne((type) => User, { eager: true })
|
||||
@ManyToOne(() => User, { eager: true })
|
||||
user: User;
|
||||
|
||||
@CreateDateColumn()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// tslint:disable: max-classes-per-file
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { EntityRepository, Repository, SelectQueryBuilder } from "typeorm";
|
||||
import { User } from "../users/user.entity";
|
||||
import { AuthSession } from "./auth-session.entity";
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
UseGuards,
|
||||
} from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { Response } from "express";
|
||||
import type { Response } from "express";
|
||||
import { User } from "../users/user.entity";
|
||||
import { AuthSession } from "./auth-session.entity";
|
||||
import { AuthService } from "./auth.service";
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
ExceptionFilter,
|
||||
ForbiddenException,
|
||||
} from "@nestjs/common";
|
||||
import { Response } from "express";
|
||||
import type { Response } from "express";
|
||||
import { Logger } from "../logger/logger.service";
|
||||
|
||||
@Catch()
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { Controller, Get } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import {
|
||||
DNSHealthIndicator,
|
||||
HealthCheck,
|
||||
HealthCheckResult,
|
||||
HealthCheckService,
|
||||
TypeOrmHealthIndicator,
|
||||
} from "@nestjs/terminus";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
|
||||
@Controller("api/v1/health")
|
||||
export class HealthCheckController {
|
||||
|
|
@ -18,7 +19,7 @@ export class HealthCheckController {
|
|||
|
||||
@Get()
|
||||
@HealthCheck()
|
||||
check() {
|
||||
check(): Promise<HealthCheckResult> {
|
||||
return this.health.check([
|
||||
() =>
|
||||
this.dns.pingCheck(
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
/* eslint-disable max-classes-per-file */
|
||||
import { Track } from "../../music-library/track.entity";
|
||||
import { User } from "../../users/user.entity";
|
||||
import { Listen } from "../listen.entity";
|
||||
|
||||
// tslint:disable max-classes-per-file
|
||||
|
||||
export class CreateListenRequestDto {
|
||||
track: Track;
|
||||
user: User;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,22 @@
|
|||
/* eslint-disable max-classes-per-file */
|
||||
import { IsDate, IsOptional, ValidateNested } from "class-validator";
|
||||
import { Interval } from "date-fns";
|
||||
import { User } from "../../users/user.entity";
|
||||
|
||||
// tslint:disable-next-line: max-classes-per-file
|
||||
export class GetListensFilterTimeDto implements Interval {
|
||||
@IsDate()
|
||||
start: Date;
|
||||
|
||||
@IsDate()
|
||||
end: Date;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: max-classes-per-file
|
||||
export class GetListensFilterDto {
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
time?: GetListensFilterTimeDto;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: max-classes-per-file
|
||||
export class GetListensDto {
|
||||
user: User;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ export class Listen {
|
|||
@PrimaryGeneratedColumn("uuid")
|
||||
id: string;
|
||||
|
||||
@ManyToOne((type) => Track)
|
||||
@ManyToOne(() => Track)
|
||||
track: Track;
|
||||
|
||||
@ManyToOne((type) => User)
|
||||
@ManyToOne(() => User)
|
||||
user: User;
|
||||
|
||||
@Column({ type: "timestamp" })
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// tslint:disable: max-classes-per-file
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { EntityRepository, Repository, SelectQueryBuilder } from "typeorm";
|
||||
import { Interval } from "../reports/interval";
|
||||
import { User } from "../users/user.entity";
|
||||
|
|
|
|||
|
|
@ -19,8 +19,13 @@ export class ListensController {
|
|||
@Query("filter") filter: GetListensFilterDto,
|
||||
@ReqUser() user: User
|
||||
): Promise<Pagination<Listen>> {
|
||||
limit = limit > 100 ? 100 : limit;
|
||||
const clampedLimit = limit > 100 ? 100 : limit;
|
||||
|
||||
return this.listensService.getListens({ page, limit, user, filter });
|
||||
return this.listensService.getListens({
|
||||
page,
|
||||
limit: clampedLimit,
|
||||
user,
|
||||
filter,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import { ConfigService } from "@nestjs/config";
|
|||
import { NestFactory } from "@nestjs/core";
|
||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
|
||||
import { AppModule } from "./app.module";
|
||||
import * as Sentry from "@sentry/node";
|
||||
import { RavenInterceptor } from "nest-raven";
|
||||
import { AppModule } from "./app.module";
|
||||
|
||||
function setupSentry(
|
||||
app: NestExpressApplication,
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@ export class Album {
|
|||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToMany((type) => Artist, (artist) => artist.albums)
|
||||
@ManyToMany(() => Artist, (artist) => artist.albums)
|
||||
@JoinTable({ name: "album_artists" })
|
||||
artists?: Artist[];
|
||||
|
||||
@OneToMany((type) => Track, (track) => track.album)
|
||||
@OneToMany(() => Track, (track) => track.album)
|
||||
tracks?: Track[];
|
||||
|
||||
@Column((type) => SpotifyLibraryDetails)
|
||||
@Column(() => SpotifyLibraryDetails)
|
||||
spotify: SpotifyLibraryDetails;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ export class Artist {
|
|||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToMany((type) => Album, (album) => album.artists)
|
||||
@ManyToMany(() => Album, (album) => album.artists)
|
||||
albums?: Album[];
|
||||
|
||||
@Column((type) => SpotifyLibraryDetails)
|
||||
@Column(() => SpotifyLibraryDetails)
|
||||
spotify: SpotifyLibraryDetails;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@ export class Track {
|
|||
@Column()
|
||||
name: string;
|
||||
|
||||
@ManyToOne((type) => Album, (album) => album.tracks)
|
||||
@ManyToOne(() => Album, (album) => album.tracks)
|
||||
album?: Album;
|
||||
|
||||
@ManyToMany((type) => Artist)
|
||||
@ManyToMany(() => Artist)
|
||||
@JoinTable({ name: "track_artists" })
|
||||
artists?: Artist[];
|
||||
|
||||
@Column((type) => SpotifyLibraryDetails)
|
||||
@Column(() => SpotifyLibraryDetails)
|
||||
spotify?: SpotifyLibraryDetails;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import { Timeframe } from "../timeframe.enum";
|
||||
|
||||
export class ListenReportDto {
|
||||
items: {
|
||||
date: string;
|
||||
|
|
|
|||
|
|
@ -264,6 +264,13 @@ export class ReportsService {
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
interval = this.getIntervalFromPreset({
|
||||
timePreset: TimePreset.LAST_7_DAYS,
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return interval;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
import {
|
||||
Injectable,
|
||||
OnApplicationBootstrap,
|
||||
OnModuleInit,
|
||||
} from "@nestjs/common";
|
||||
import { Injectable, OnApplicationBootstrap } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { SchedulerRegistry } from "@nestjs/schedule";
|
||||
import { captureException } from "@sentry/node";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { Module } from "@nestjs/common";
|
||||
import { ConfigModule } from "../config/config.module";
|
||||
import { SchedulerService } from "./scheduler.service";
|
||||
import { SpotifyModule } from "./spotify/spotify.module";
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ export class SpotifyApiService {
|
|||
|
||||
async getRecentlyPlayedTracks({
|
||||
accessToken,
|
||||
lastRefreshTime,
|
||||
}: SpotifyConnection): Promise<PlayHistoryObject[]> {
|
||||
const parameters: { limit: number; after?: number } = {
|
||||
limit: 50,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ export class SpotifyService {
|
|||
const users = await this.usersService.findAll();
|
||||
|
||||
for (const user of users) {
|
||||
// We want to run this sequentially to avoid rate limits
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await this.crawlListensForUser(user);
|
||||
}
|
||||
}
|
||||
|
|
@ -142,7 +144,7 @@ export class SpotifyService {
|
|||
spotifyID
|
||||
);
|
||||
} catch (err) {
|
||||
if (err.response && err.response.status === 401) {
|
||||
if (err.response && err.response.status === 401 && retryOnExpiredToken) {
|
||||
await this.refreshAppAccessToken();
|
||||
|
||||
return this.importTrack(spotifyID, false);
|
||||
|
|
@ -192,7 +194,7 @@ export class SpotifyService {
|
|||
spotifyID
|
||||
);
|
||||
} catch (err) {
|
||||
if (err.response && err.response.status === 401) {
|
||||
if (err.response && err.response.status === 401 && retryOnExpiredToken) {
|
||||
await this.refreshAppAccessToken();
|
||||
|
||||
return this.importAlbum(spotifyID, false);
|
||||
|
|
@ -238,7 +240,7 @@ export class SpotifyService {
|
|||
spotifyID
|
||||
);
|
||||
} catch (err) {
|
||||
if (err.response && err.response.status === 401) {
|
||||
if (err.response && err.response.status === 401 && retryOnExpiredToken) {
|
||||
await this.refreshAppAccessToken();
|
||||
|
||||
return this.importArtist(spotifyID, false);
|
||||
|
|
@ -261,6 +263,8 @@ export class SpotifyService {
|
|||
private async refreshAppAccessToken(): Promise<void> {
|
||||
if (!this.appAccessTokenInProgress) {
|
||||
this.logger.debug("refreshing spotify app access token");
|
||||
/* eslint-disable no-async-promise-executor */
|
||||
|
||||
this.appAccessTokenInProgress = new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const newAccessToken =
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Entity, Column, PrimaryGeneratedColumn, OneToOne } from "typeorm";
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||
import { SpotifyConnection } from "../sources/spotify/spotify-connection.entity";
|
||||
|
||||
@Entity()
|
||||
|
|
@ -12,6 +12,6 @@ export class User {
|
|||
@Column({ nullable: true })
|
||||
photo?: string;
|
||||
|
||||
@Column((type) => SpotifyConnection)
|
||||
@Column(() => SpotifyConnection)
|
||||
spotify: SpotifyConnection;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export class UsersService {
|
|||
user: User,
|
||||
spotify: SpotifyConnection
|
||||
): Promise<void> {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
user.spotify = spotify;
|
||||
await this.userRepository.save(user);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ describe("AppController (e2e)", () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule]
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = moduleFixture.createNestApplication();
|
||||
|
|
|
|||
23
tslint.json
23
tslint.json
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"defaultSeverity": "error",
|
||||
"extends": [
|
||||
"tslint:recommended",
|
||||
"tslint-config-prettier",
|
||||
"tslint-plugin-prettier"
|
||||
],
|
||||
"jsRules": {
|
||||
"no-unused-expression": true
|
||||
},
|
||||
"rules": {
|
||||
"member-access": [false],
|
||||
"ordered-imports": [false],
|
||||
"max-line-length": [true, 150],
|
||||
"member-ordering": [false],
|
||||
"interface-name": [false],
|
||||
"arrow-parens": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"trailing-comma": false,
|
||||
"prettier": "true"
|
||||
},
|
||||
"rulesDirectory": []
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue