Skip to content

Commit

Permalink
Upgrade to Bun v1.2 and fix lint workflow (#194)
Browse files Browse the repository at this point in the history
* chore: migrate to v1.2's jsonc lockfile

* ci: migrate workflow to Bun

* fix: modify working-directory for monorepo

* chore: upgrade dependencies

* chore: add recommended extensions

* chore: add mjs, cjs files to eslint config

* chore: upgrade eslint version to fix linting

* chore: refresh eslint cache

* chore: fix eslint on backend

* chore: fix all auto-fixable eslint errors

* chore: change several lints to warn

* fix: fix several eslint violations

* style: run format on all files
  • Loading branch information
ap-1 authored Jan 25, 2025
1 parent 788dfbc commit 7875a78
Show file tree
Hide file tree
Showing 75 changed files with 5,218 additions and 928 deletions.
38 changes: 19 additions & 19 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,27 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: oven-sh/setup-bun@v2

- name: Install dependencies
working-directory: .
run: npm i
shell: bash
run: bun install

- name: Generate prisma client
working-directory: .
run: npm run db-generate
shell: bash
- name: Check TypeScript (Frontend)
working-directory: ./frontend
run: npx tsc --noEmit
shell: bash
working-directory: ./packages/db
run: bun run db-generate

- name: Run ESLint (Frontend)
working-directory: ./frontend
run: npm run lint
shell: bash
working-directory: ./apps/frontend
run: bun run lint

- name: Check TypeScript (Frontend)
working-directory: ./apps/frontend
run: bunx tsc --noEmit

- name: Run ESLint (Backend)
working-directory: ./backend
run: npm run lint
shell: bash
working-directory: ./apps/backend
run: bun run lint

- name: Check TypeScript (Backend)
working-directory: ./backend
run: npx tsc --noEmit
shell: bash
working-directory: ./apps/backend
run: bunx tsc --noEmit
3 changes: 3 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["dbaeumer.vscode-eslint", "nrwl.angular-console", "esbenp.prettier-vscode"]
}
23 changes: 3 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
# CMU Courses


CMU Courses (AKA ScottyLabs Course Tool) is a web application designed to aid students at Carnegie Mellon University in
browsing courses, including information about course evaluations and schedules. It is actively maintained
by [ScottyLabs](https://scottylabs.org).


This is the second iteration of the Course Tool. The second version is a rewrite of the frontend and backend, with the
inclusion of new features (currently a work-in-progress) such as:


- Search
- Filters
- Professor Search
- Schedule Creation


This new version is currently deployed at [cmucourses.com](https://cmucourses.com). This project is currently undergoing
development, so expect large changes to the codebase and features to be unstable.


## Getting Started
To get started, create a codespace from the github repository, then open it in VScode.

To get started, create a codespace from the github repository, then open it in VScode.

Navigate to the terminal and install bun by running the following commands:
Navigate to the terminal and install bun by running the following commands:

```
curl -fsSL https://bun.sh/install | bash
Expand All @@ -36,35 +31,23 @@ bun run dev
Create a .env file in your root directory, and add the following line to the file:
NEXT_PUBLIC_BACKEND_URL="http://localhost:3000"


If course descriptions are not loading, set the public backend url to the local address of the 3000 port. (Make sure that the URL does not have the trailing backslash.)


Ensure both 3000 and 3010 ports are set to public visibility.


### Running local build


Preview the local version of the code by right clicking on the 3010 port and view CMUcourses on your browser.

Preview the local version of the code by right clicking on the 3010 port and view CMUcourses on your browser.

### Scrapers


More information about the scrapers used to collect the data may be found
at [this repo](https://github.com/ScottyLabs/course-scraper/).


## Technologies


The Course Tool is built with several technologies.


- The frontend is built using NextJS and React, Redux, Typescript and TailwindCSS.
- The backend uses Express, MongoDB and JS.
- The scrapers are written in JS.



23 changes: 0 additions & 23 deletions apps/backend/.eslintrc.json

This file was deleted.

29 changes: 29 additions & 0 deletions apps/backend/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import globals from "globals";
import tsParser from "@typescript-eslint/parser";
import path from "node:path";
import { fileURLToPath } from "node:url";
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});

export default [
...compat.extends("eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"),
{
languageOptions: {
globals: {
...globals.node,
},

parser: tsParser,
ecmaVersion: "latest",
sourceType: "module",
},
},
];
36 changes: 21 additions & 15 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,35 @@
"start": "bun run ./build/app.js",
"dev": "bun --watch src/app.ts",
"build": "bun build ./src/app.ts --target=bun --outdir=build",
"format": "prettier --write . --ignore-path .gitignore",
"lint": "./node_modules/.bin/eslint ./src/**"
"lint": "eslint ./src/**"
},
"dependencies": {
"@clerk/clerk-sdk-node": "^5.0.30",
"@clerk/clerk-sdk-node": "^5.1.6",
"@cmucourses/db": "workspace:*",
"@types/jsonwebtoken": "^9.0.6",
"axios": "^0.27.1",
"@types/jsonwebtoken": "^9.0.8",
"axios": "^0.27.2",
"cors": "^2.8.5",
"express": "^4.18.0",
"express": "^4.21.2",
"jsonwebtoken": "^9.0.2",
"morgan": "^1.10.0",
"node": "^22.7.0",
"node-cron": "^3.0.0",
"node": "^22.13.1",
"node-cron": "^3.0.3",
"passlink-server": "^1.1.0"
},
"devDependencies": {
"@types/cors": "^2.8.13",
"@types/express": "^4.17.17",
"@types/morgan": "^1.9.5",
"@types/node": "^18.15.3",
"@types/node-cron": "^3.0.7",
"bun": "^1.1.26",
"eslint-config-prettier": "^8.7.0"
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0",
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/morgan": "^1.9.9",
"@types/node": "^18.19.74",
"@types/node-cron": "^3.0.11",
"@typescript-eslint/eslint-plugin": "^8.21.0",
"@typescript-eslint/parser": "^8.21.0",
"eslint": "^9.19.0",
"eslint-config-prettier": "^10.0.1",
"globals": "^15.14.0",
"prettier": "^3.4.2",
"typescript": "^5.7.3"
}
}
13 changes: 6 additions & 7 deletions apps/backend/src/controllers/courses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export const getFilteredCourses: RequestHandler<
try {
const session = JSON.parse(serializedSession);
return [{ year: parseInt(session.year), semester: session.semester }];
} catch (e) {
} catch {
// SyntaxError
return [];
}
Expand Down Expand Up @@ -274,11 +274,10 @@ export const getAllCourses: RequestHandler<
}
};


export const getRequisites: RequestHandler = async (req, res, next) => {
try {
if (!req.params.courseID) {
return res.status(400).json({ error: 'courseID parameter is required' });
return res.status(400).json({ error: "courseID parameter is required" });
}

const courseID = standardizeID(req.params.courseID);
Expand All @@ -293,7 +292,7 @@ export const getRequisites: RequestHandler = async (req, res, next) => {
});

if (!course) {
return res.status(400).json({ error: 'Course not found' });
return res.status(400).json({ error: "Course not found" });
}

const parsedPrereqs = parsePrereqString(course.prereqString);
Expand All @@ -309,13 +308,13 @@ export const getRequisites: RequestHandler = async (req, res, next) => {
},
});

const postreqIDs = postreqs.map(postreq => postreq.courseID);
const postreqIDs = postreqs.map((postreq) => postreq.courseID);

const courseRequisites = {
prereqs: course.prereqs,
prereqRelations: parsedPrereqs,
postreqs: postreqIDs
}
postreqs: postreqIDs,
};

res.json(courseRequisites);
} catch (e) {
Expand Down
27 changes: 11 additions & 16 deletions apps/backend/src/controllers/geneds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,20 @@ export const getGeneds: RequestHandler<
> = async (req, res, next) => {
try {
if ("school" in req.query) {
const school = req.query.school
const school = req.query.school;
const geneds = await db.geneds.findMany({
select: {
courseID: true,
tags: true,
},
where: {
school
}
school,
},
});

const proccesedGeneds = Object.fromEntries(
geneds.map((gened) => [gened.courseID, gened])
);
const proccesedGeneds = Object.fromEntries(geneds.map((gened) => [gened.courseID, gened]));
const courseIDs = Object.keys(proccesedGeneds);


const courses = await db.courses.findMany({
select: {
courseID: true,
Expand All @@ -64,23 +61,21 @@ export const getGeneds: RequestHandler<
},
where: {
courseID: {
in: courseIDs
}
}
in: courseIDs,
},
},
});

const processedCourses = Object.fromEntries(
courses.map((course) => [course.courseID, course])
);
const processedCourses = Object.fromEntries(courses.map((course) => [course.courseID, course]));

let fces;
if (req.body.token) {
fces = await db.fces.findMany({
where: {
courseID: {
in: courseIDs
}
}
in: courseIDs,
},
},
});
}

Expand Down
8 changes: 4 additions & 4 deletions apps/backend/src/controllers/instructors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { RequestHandler } from "express";
import { PrismaReturn } from "~/util";
import db from "@cmucourses/db";

const getAllInstructorsDbQuery = {
type GetAllInstructorsDbQuery = {
select: {
instructor: true,
},
instructor: true;
};
};

export interface GetInstructors {
params: unknown;
resBody: PrismaReturn<typeof db.fces.findMany<typeof getAllInstructorsDbQuery>>;
resBody: PrismaReturn<typeof db.fces.findMany<GetAllInstructorsDbQuery>>;
reqBody: unknown;
query: unknown;
}
Expand Down
8 changes: 4 additions & 4 deletions apps/backend/src/controllers/schedules.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ElemType, exclude, PrismaReturn, singleToArray, standardizeID } from "~/util";
import {RequestHandler} from "express";
import { RequestHandler } from "express";
import db from "@cmucourses/db";

type schedule = ElemType<PrismaReturn<typeof db.schedules.findMany>>;
Expand Down Expand Up @@ -27,7 +27,7 @@ export const getSchedules: RequestHandler<
});
const projectedResults = schedules.map((courseFce) => exclude(courseFce, "id", "v"));
res.json(projectedResults);
} catch(e) {
} catch (e) {
next(e);
}
} else if ("courseID" in req.query) {
Expand All @@ -40,8 +40,8 @@ export const getSchedules: RequestHandler<
});
const projectedResults = schedules.map((courseFce) => exclude(courseFce, "id", "v"));
res.json(projectedResults);
} catch(e) {
} catch (e) {
next(e);
}
}
};
};
4 changes: 2 additions & 2 deletions apps/backend/src/controllers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ const verifyUserToken = async (token: string) => {
const pubkey = process.env.CLERK_PEM_KEY || "";

const payload = jwt.verify(token, pubkey, {
algorithms: ["RS256"]
algorithms: ["RS256"],
});

const currentTime = Math.floor(Date.now() / 1000);
const BACKEND_ENV = process.env.BACKEND_ENV || "dev";
const CLERK_LOGIN_HOST = process.env.CLERK_LOGIN_HOST || "http://localhost:3010";

if (!payload || typeof payload === 'string') {
if (!payload || typeof payload === "string") {
throw "No token present. Did you forget to pass in the token with the API call?";
} else if (payload.exp && payload.exp < currentTime) {
throw "Token has expired.";
Expand Down
Loading

0 comments on commit 7875a78

Please sign in to comment.