From a989d6b9173ab3b685872e5c9f6d2062b5ac30ed Mon Sep 17 00:00:00 2001 From: Raymond Wang Date: Sat, 22 Oct 2022 19:41:27 -0700 Subject: [PATCH] begin implement linter --- .eslintrc.json | 27 ++++++ package-lock.json | 112 ++++++++++++++++++++++- package.json | 17 +--- src/Database.ts | 10 +- src/index.ts | 19 ++-- src/public/Config.ts | 2 +- src/public/committees.tsx | 8 +- src/public/components/Carousel.tsx | 5 +- src/public/components/CarouselItem.tsx | 6 +- src/public/components/CarouselPage.tsx | 8 +- src/public/components/DefaultSection.tsx | 9 +- src/public/components/Footer.tsx | 8 +- src/public/components/InvolveBox.tsx | 6 +- src/public/components/SocialCard.tsx | 6 +- src/public/components/Splash.tsx | 2 +- src/public/components/TopBar.tsx | 2 +- src/public/events.tsx | 12 +-- src/public/index.tsx | 8 +- src/public/projects.tsx | 11 +-- 19 files changed, 188 insertions(+), 90 deletions(-) create mode 100644 .eslintrc.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..3b4b96c --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,27 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es6": true, + "jest": true, + "node": true + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:@typescript-eslint/recommended" + ], + "overrides": [], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest" + }, + "plugins": ["react", "@typescript-eslint"], + "rules": {}, + "settings": { + "react": { + "version": "detect" + } + }, + "ignorePatterns": ["node_modules/", "dist/", "build/", "webpack.config.*"] +} diff --git a/package-lock.json b/package-lock.json index a880244..326bf97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,7 @@ "": { "name": "ieee-website", "version": "1.0.0", - "license": "ISC", + "license": "MIT", "dependencies": { "@types/express": "^4.17.13", "@types/node": "^16.11.7", @@ -24,13 +24,16 @@ "@babel/preset-react": "^7.14.5", "@types/react": "^16.14.20", "@typescript-eslint/eslint-plugin": "^5.40.1", + "@typescript-eslint/parser": "^5.40.1", "babel-loader": "^8.2.3", "copy-webpack-plugin": "^6.4.1", "css-loader": "^5.2.7", "eslint": "^8.26.0", + "eslint-config-prettier": "^8.5.0", "eslint-config-standard-with-typescript": "^23.0.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-n": "^15.3.0", + "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-promise": "^6.1.1", "eslint-plugin-react": "^7.31.10", "html-webpack-plugin": "^4.5.2", @@ -39,7 +42,7 @@ "ts-loader": "^8.3.0", "typescript": "^4.8.4", "webpack": "^5.60.0", - "webpack-cli": "^4.9.1" + "webpack-cli": "^4.10.0" } }, "node_modules/@ampproject/remapping": { @@ -3913,6 +3916,18 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-config-standard": { "version": "17.0.0", "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", @@ -4139,6 +4154,27 @@ "node": ">=10" } }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-promise": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", @@ -4637,6 +4673,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -6608,6 +6650,34 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "peer": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-error": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", @@ -11215,6 +11285,13 @@ } } }, + "eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "requires": {} + }, "eslint-config-standard": { "version": "17.0.0", "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", @@ -11374,6 +11451,15 @@ } } }, + "eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, "eslint-plugin-promise": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", @@ -11596,6 +11682,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -13034,6 +13126,22 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "peer": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "pretty-error": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", diff --git a/package.json b/package.json index e201a08..eba2a15 100644 --- a/package.json +++ b/package.json @@ -5,17 +5,7 @@ "main": "build/index.js", "scripts": { "build": "webpack & tsc", - "watch": "npm-watch build" - }, - "watch": { - "build": { - "patterns": [ - "src" - ], - "quiet": true, - "silent": true, - "extensions": "js,jsx,ts,tsx,html,css" - } + "lint": "eslint \"**/*.{ts, tsx}\"" }, "keywords": [], "author": "", @@ -36,13 +26,16 @@ "@babel/preset-react": "^7.14.5", "@types/react": "^16.14.20", "@typescript-eslint/eslint-plugin": "^5.40.1", + "@typescript-eslint/parser": "^5.40.1", "babel-loader": "^8.2.3", "copy-webpack-plugin": "^6.4.1", "css-loader": "^5.2.7", "eslint": "^8.26.0", + "eslint-config-prettier": "^8.5.0", "eslint-config-standard-with-typescript": "^23.0.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-n": "^15.3.0", + "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-promise": "^6.1.1", "eslint-plugin-react": "^7.31.10", "html-webpack-plugin": "^4.5.2", @@ -51,6 +44,6 @@ "ts-loader": "^8.3.0", "typescript": "^4.8.4", "webpack": "^5.60.0", - "webpack-cli": "^4.9.1" + "webpack-cli": "^4.10.0" } } \ No newline at end of file diff --git a/src/Database.ts b/src/Database.ts index 322a4eb..c885b0a 100644 --- a/src/Database.ts +++ b/src/Database.ts @@ -1,4 +1,4 @@ -import { Schema, Document, LeanDocument } from "mongoose"; +import { Schema, Document } from "mongoose"; import * as mongoose from "mongoose"; import { promisify } from "util"; import { randomBytes, pbkdf2 } from "crypto"; @@ -99,7 +99,7 @@ export default class UserDatabase { * @param newPassword the user's new password */ public async setPassword(uuid: string, newPassword: string) { - let hashsalt = await UserDatabase.hash(newPassword); + const hashsalt = await UserDatabase.hash(newPassword); await User.findOneAndUpdate( { uuid: uuid }, { password: hashsalt } @@ -191,7 +191,7 @@ export default class UserDatabase { title?: string, isOfficer?: boolean ): Promise { - let encrypted = await UserDatabase.hash(password); + const encrypted = await UserDatabase.hash(password); await new User({ display: display, email: email, @@ -210,8 +210,8 @@ export default class UserDatabase { * @returns the hashed password */ public static async hash(password: string): Promise { - let salt = randomBytes(UserDatabase.SALT_LENGTH); - let pass = Buffer.from(String.prototype.normalize(password)); + const salt = randomBytes(UserDatabase.SALT_LENGTH); + const pass = Buffer.from(String.prototype.normalize(password)); return { hash: await pbkdf( pass, diff --git a/src/index.ts b/src/index.ts index 632563c..51a5c94 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,7 @@ -import express from "express"; +import express, { NextFunction } from "express"; import { Request, Response } from "express"; import * as path from "path"; import * as fs from "fs"; -import UserDatabase from "./Database"; interface Website { [key: string]: string; @@ -66,7 +65,7 @@ const PORT = 9000; // Make the public directory traversible to people online APP.use(express.static(path.join(__dirname, "public"))); // Put the cookies as a variable in the request -APP.use((req: Request, res: Response, next: any) => { +APP.use((req: Request, res: Response, next: NextFunction) => { req.cookies = req.headers.cookie; next(); }); @@ -94,7 +93,7 @@ APP.get("/contact", (req: Request, res: Response) => { /** * Utility functions for above methods */ -function respond(res: any, filename: string) { +function respond(res: Response, filename: string) { res.set({ "Content-Type": "text/html", }); @@ -102,19 +101,21 @@ function respond(res: any, filename: string) { } function generatePage(name: string): string { - let site = WEBSITES.find((e) => e.sitename === name); + const site = WEBSITES.find((e) => e.sitename === name); let html = TEMPLATE; - for (let key of Object.keys(site)) { + let key; + for (key of Object.keys(site)) { html = html.replace(new RegExp("\\$" + key.toUpperCase()), site[key]); } return html; } function generateFilePages() { - for (let site of WEBSITES) { - let html = generatePage(site.sitename); + let site; + for (site of WEBSITES) { + const html = generatePage(site.sitename); fs.writeFileSync( - require("path").join(__dirname, "public/", `${site.sitename}.html`), + path.join(__dirname, "public/", `${site.sitename}.html`), html ); } diff --git a/src/public/Config.ts b/src/public/Config.ts index c4a4a03..d148131 100644 --- a/src/public/Config.ts +++ b/src/public/Config.ts @@ -25,7 +25,7 @@ export const ACTIVE_PAGES = [ // Urls of team photos that will go in the "About" slideshow export const TEAM_PHOTOS: string[] = []; export const PROJECT_SPACE: string[] = []; -export const EVENTS: any[] = []; +export const EVENTS: unknown[] = []; export const SOCIALS = [ { diff --git a/src/public/committees.tsx b/src/public/committees.tsx index f3832ba..3352bba 100644 --- a/src/public/committees.tsx +++ b/src/public/committees.tsx @@ -9,11 +9,8 @@ import SocialCard from "./components/SocialCard"; import Carousel from "./components/Carousel"; import Footer from "./components/Footer"; -interface MainProps {} -interface MainState {} - -class Main extends React.Component { - constructor(props: MainProps) { +class Main extends React.Component { + constructor(props: any) { super(props); this.state = {}; } @@ -67,6 +64,7 @@ class Main extends React.Component {
{[...EMAIL, ...SOCIALS].map((n) => ( { } public render() { - let arr = this.chunkArray(this.props.items); + const arr = this.chunkArray(this.props.items); return (
{
{arr.map((items, i) => ( @@ -72,7 +73,7 @@ export default class Carousel extends Component { } private chunkArray(array: CarouselItemProps[]): CarouselItemProps[][] { - let returnArr = [] as CarouselItemProps[][]; + const returnArr = [] as CarouselItemProps[][]; for (let i = 0; i < array.length; i += this.props.itemsPerPage) { returnArr.push(array.slice(i, i + this.props.itemsPerPage)); } diff --git a/src/public/components/CarouselItem.tsx b/src/public/components/CarouselItem.tsx index 9b499d1..a8e7b1c 100644 --- a/src/public/components/CarouselItem.tsx +++ b/src/public/components/CarouselItem.tsx @@ -7,12 +7,8 @@ export interface CarouselItemProps { email: string; photo: string; } -interface CarouselItemState {} -export default class CarouselItem extends Component< - CarouselItemProps, - CarouselItemState -> { +export default class CarouselItem extends Component { constructor(props: CarouselItemProps) { super(props); this.state = {}; diff --git a/src/public/components/CarouselPage.tsx b/src/public/components/CarouselPage.tsx index e8a8389..a77651f 100644 --- a/src/public/components/CarouselPage.tsx +++ b/src/public/components/CarouselPage.tsx @@ -6,12 +6,8 @@ interface CarouselPageProps { items: CarouselItemProps[]; visible: boolean; } -interface CarouselPageState {} -export default class CarouselPage extends Component< - CarouselPageProps, - CarouselPageState -> { +export default class CarouselPage extends Component { constructor(props: CarouselPageProps) { super(props); this.state = {}; @@ -24,7 +20,7 @@ export default class CarouselPage extends Component< style={this.props.visible ? {} : { display: "none" }} > {this.props.items.map((n) => ( - + ))}
); diff --git a/src/public/components/DefaultSection.tsx b/src/public/components/DefaultSection.tsx index 9d69a71..20333ee 100644 --- a/src/public/components/DefaultSection.tsx +++ b/src/public/components/DefaultSection.tsx @@ -6,12 +6,8 @@ interface DefaultSectionProps { paragraphs?: string[]; className?: string; } -interface DefaultSectionState {} -export default class DefaultSection extends Component< - DefaultSectionProps, - DefaultSectionState -> { +export default class DefaultSection extends Component { constructor(props: DefaultSectionProps) { super(props); this.state = {}; @@ -27,9 +23,10 @@ export default class DefaultSection extends Component<
{this.props.title}
{(this.props.paragraphs ? this.props.paragraphs : []).map( (n) => ( -

{n}

+

{n}

) )} + {/* eslint-disable-next-line react/prop-types */} {this.props.children}
); diff --git a/src/public/components/Footer.tsx b/src/public/components/Footer.tsx index d29ae96..0861f81 100644 --- a/src/public/components/Footer.tsx +++ b/src/public/components/Footer.tsx @@ -3,11 +3,8 @@ import { Component } from "react"; import SocialCard from "./SocialCard"; import { EMAIL_WHITE, SOCIALS_WHITE } from "../Config"; -interface FooterProps {} -interface FooterState {} - -export default class Footer extends Component { - constructor(props: FooterProps) { +export default class Footer extends Component { + constructor(props: any) { super(props); this.state = {}; } @@ -19,6 +16,7 @@ export default class Footer extends Component {
{[...EMAIL_WHITE, ...SOCIALS_WHITE].map((n) => ( { +export default class InvolveBox extends Component { constructor(props: InvolveBoxProps) { super(props); this.state = {}; diff --git a/src/public/components/SocialCard.tsx b/src/public/components/SocialCard.tsx index c007d6b..a0263a8 100644 --- a/src/public/components/SocialCard.tsx +++ b/src/public/components/SocialCard.tsx @@ -6,12 +6,8 @@ interface SocialCardProps { image: string; message: string; } -interface SocialCardState {} -export default class SocialCard extends Component< - SocialCardProps, - SocialCardState -> { +export default class SocialCard extends Component { constructor(props: SocialCardProps) { super(props); this.state = {}; diff --git a/src/public/components/Splash.tsx b/src/public/components/Splash.tsx index d70ec12..7a2cbbe 100644 --- a/src/public/components/Splash.tsx +++ b/src/public/components/Splash.tsx @@ -21,7 +21,7 @@ export default class Splash extends Component { this.interval = setInterval( this.changeImage.bind(this), this.props.delay - ) as any as number; + ) as unknown as number; } private changeImage(): void { diff --git a/src/public/components/TopBar.tsx b/src/public/components/TopBar.tsx index 13d7bd9..a93c387 100644 --- a/src/public/components/TopBar.tsx +++ b/src/public/components/TopBar.tsx @@ -69,7 +69,7 @@ export default class TopBar extends Component { > {this.props.links.map((l) => { return ( - + {l.name} ); diff --git a/src/public/events.tsx b/src/public/events.tsx index 9debb63..9f2cfcb 100644 --- a/src/public/events.tsx +++ b/src/public/events.tsx @@ -1,19 +1,14 @@ import * as ReactDom from "react-dom"; import * as React from "react"; import TopBar from "./components/TopBar"; -import { ACTIVE_PAGES, SOCIALS, EMAIL, OFFICERS } from "./Config"; +import { ACTIVE_PAGES, SOCIALS, EMAIL } from "./Config"; import Splash from "./components/Splash"; import DefaultSection from "./components/DefaultSection"; -import InvolveBox from "./components/InvolveBox"; import SocialCard from "./components/SocialCard"; -import Carousel from "./components/Carousel"; import Footer from "./components/Footer"; -interface MainProps {} -interface MainState {} - -class Main extends React.Component { - constructor(props: MainProps) { +class Main extends React.Component { + constructor(props: any) { super(props); this.state = {}; } @@ -51,6 +46,7 @@ class Main extends React.Component {
{[...EMAIL, ...SOCIALS].map((n) => ( { - constructor(props: MainProps) { +class Main extends React.Component { + constructor(props: any) { super(props); this.state = {}; } @@ -84,6 +81,7 @@ class Main extends React.Component {
{[...EMAIL, ...SOCIALS].map((n) => ( { - constructor(props: MainProps) { +class Main extends React.Component { + constructor(props: any) { super(props); this.state = {}; } @@ -78,6 +74,7 @@ class Main extends React.Component {
{[...EMAIL, ...SOCIALS].map((n) => (